mirror of
https://github.com/github/codeql.git
synced 2025-12-22 11:46:32 +01:00
Merge pull request #792 from rdmarsh2/rdmarsh/cpp/escape-analysis
C++: Interprocedural escape/alias analysis in IR construction
This commit is contained in:
@@ -1310,6 +1310,13 @@ class CallInstruction extends Instruction {
|
|||||||
result = getAnOperand()
|
result = getAnOperand()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the `Function` that the call targets, if this is statically known.
|
||||||
|
*/
|
||||||
|
final Function getStaticCallTarget() {
|
||||||
|
result = getCallTarget().(FunctionInstruction).getFunctionSymbol()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all of the arguments of the call, including the `this` pointer, if any.
|
* Gets all of the arguments of the call, including the `this` pointer, if any.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import cpp
|
|||||||
private import InputIR
|
private import InputIR
|
||||||
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||||
|
|
||||||
|
private import semmle.code.cpp.models.interfaces.Alias
|
||||||
|
|
||||||
private class IntValue = Ints::IntValue;
|
private class IntValue = Ints::IntValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,7 +48,7 @@ private IntValue getFieldBitOffset(Field field) {
|
|||||||
* not result in any address held in that operand from escaping beyond the
|
* not result in any address held in that operand from escaping beyond the
|
||||||
* instruction.
|
* instruction.
|
||||||
*/
|
*/
|
||||||
predicate operandIsConsumedWithoutEscaping(Operand operand) {
|
private predicate operandIsConsumedWithoutEscaping(Operand operand) {
|
||||||
// The source/destination address of a Load/Store does not escape (but the
|
// The source/destination address of a Load/Store does not escape (but the
|
||||||
// loaded/stored value could).
|
// loaded/stored value could).
|
||||||
operand instanceof AddressOperand or
|
operand instanceof AddressOperand or
|
||||||
@@ -60,7 +62,18 @@ predicate operandIsConsumedWithoutEscaping(Operand operand) {
|
|||||||
// Converting an address to a `bool` does not escape the address.
|
// Converting an address to a `bool` does not escape the address.
|
||||||
instr.(ConvertInstruction).getResultType() instanceof BoolType
|
instr.(ConvertInstruction).getResultType() instanceof BoolType
|
||||||
)
|
)
|
||||||
)
|
) or
|
||||||
|
// Some standard function arguments never escape
|
||||||
|
isNeverEscapesArgument(operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate operandEscapesDomain(Operand operand) {
|
||||||
|
not operandIsConsumedWithoutEscaping(operand) and
|
||||||
|
not operandIsPropagated(operand, _) and
|
||||||
|
not isArgumentForParameter(_, operand, _) and
|
||||||
|
not isOnlyEscapesViaReturnArgument(operand) and
|
||||||
|
not operand.getUseInstruction() instanceof ReturnValueInstruction and
|
||||||
|
not operand instanceof PhiOperand
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,7 +111,7 @@ IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
|
|||||||
* `bitOffset`. If the address is propagated, but the offset is not known to be
|
* `bitOffset`. If the address is propagated, but the offset is not known to be
|
||||||
* a constant, then `bitOffset` is unknown.
|
* a constant, then `bitOffset` is unknown.
|
||||||
*/
|
*/
|
||||||
predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
||||||
exists(Instruction instr |
|
exists(Instruction instr |
|
||||||
instr = operand.getUseInstruction() and
|
instr = operand.getUseInstruction() and
|
||||||
(
|
(
|
||||||
@@ -134,34 +147,134 @@ predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
|||||||
// offset of the field.
|
// offset of the field.
|
||||||
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
|
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
|
||||||
// A copy propagates the source value.
|
// A copy propagates the source value.
|
||||||
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
|
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0 or
|
||||||
|
// Some functions are known to propagate an argument
|
||||||
|
isAlwaysReturnedArgument(operand) and bitOffset = 0
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private predicate operandEscapesNonReturn(Operand operand) {
|
||||||
* Holds if any address held in operand number `tag` of instruction `instr`
|
// The address is propagated to the result of the instruction, and that result itself is returned
|
||||||
* escapes outside the domain of the analysis.
|
operandIsPropagated(operand, _) and resultEscapesNonReturn(operand.getUseInstruction())
|
||||||
*/
|
or
|
||||||
predicate operandEscapes(Operand operand) {
|
// The operand is used in a function call which returns it, and the return value is then returned
|
||||||
// Conservatively assume that the address escapes unless one of the following
|
exists(CallInstruction ci, Instruction init |
|
||||||
// holds:
|
isArgumentForParameter(ci, operand, init) and
|
||||||
not (
|
(
|
||||||
// The operand is used in a way that does not escape the instruction
|
resultMayReachReturn(init) and
|
||||||
operandIsConsumedWithoutEscaping(operand) or
|
resultEscapesNonReturn(ci)
|
||||||
// The address is propagated to the result of the instruction, but that
|
or
|
||||||
// result does not itself escape.
|
resultEscapesNonReturn(init)
|
||||||
operandIsPropagated(operand, _) and not resultEscapes(operand.getUseInstruction())
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUseInstruction())
|
||||||
|
or
|
||||||
|
operand instanceof PhiOperand and
|
||||||
|
resultEscapesNonReturn(operand.getUseInstruction())
|
||||||
|
or
|
||||||
|
operandEscapesDomain(operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate operandMayReachReturn(Operand operand) {
|
||||||
|
// The address is propagated to the result of the instruction, and that result itself is returned
|
||||||
|
operandIsPropagated(operand, _) and
|
||||||
|
resultMayReachReturn(operand.getUseInstruction())
|
||||||
|
or
|
||||||
|
// The operand is used in a function call which returns it, and the return value is then returned
|
||||||
|
exists(CallInstruction ci, Instruction init |
|
||||||
|
isArgumentForParameter(ci, operand, init) and
|
||||||
|
resultMayReachReturn(init) and
|
||||||
|
resultMayReachReturn(ci)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// The address is returned
|
||||||
|
operand.getUseInstruction() instanceof ReturnValueInstruction
|
||||||
|
or
|
||||||
|
isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUseInstruction())
|
||||||
|
or
|
||||||
|
operand instanceof PhiOperand and
|
||||||
|
resultMayReachReturn(operand.getUseInstruction())
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate operandReturned(Operand operand, IntValue bitOffset) {
|
||||||
|
// The address is propagated to the result of the instruction, and that result itself is returned
|
||||||
|
exists(IntValue bitOffset1, IntValue bitOffset2 |
|
||||||
|
operandIsPropagated(operand, bitOffset1) and
|
||||||
|
resultReturned(operand.getUseInstruction(), bitOffset2) and
|
||||||
|
bitOffset = Ints::add(bitOffset1, bitOffset2)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// The operand is used in a function call which returns it, and the return value is then returned
|
||||||
|
exists(CallInstruction ci, Instruction init, IntValue bitOffset1, IntValue bitOffset2 |
|
||||||
|
isArgumentForParameter(ci, operand, init) and
|
||||||
|
resultReturned(init, bitOffset1) and
|
||||||
|
resultReturned(ci, bitOffset2) and
|
||||||
|
bitOffset = Ints::add(bitOffset1, bitOffset2)
|
||||||
|
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// The address is returned
|
||||||
|
operand.getUseInstruction() instanceof ReturnValueInstruction and
|
||||||
|
bitOffset = 0
|
||||||
|
or
|
||||||
|
isOnlyEscapesViaReturnArgument(operand) and resultReturned(operand.getUseInstruction(), _) and
|
||||||
|
bitOffset = Ints::unknown()
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) {
|
||||||
|
exists(Function f |
|
||||||
|
ci = operand.getUseInstruction() and
|
||||||
|
f = ci.getStaticCallTarget() and
|
||||||
|
(
|
||||||
|
init.(InitializeParameterInstruction).getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex())
|
||||||
|
or
|
||||||
|
init instanceof InitializeThisInstruction and
|
||||||
|
init.getEnclosingFunction() = f and
|
||||||
|
operand instanceof ThisArgumentOperand
|
||||||
|
) and
|
||||||
|
not f.isVirtual() and
|
||||||
|
not f instanceof AliasFunction
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isAlwaysReturnedArgument(Operand operand) {
|
||||||
|
exists(AliasFunction f |
|
||||||
|
f = operand.getUseInstruction().(CallInstruction).getStaticCallTarget() and
|
||||||
|
f.parameterIsAlwaysReturned(operand.(PositionalArgumentOperand).getIndex())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isOnlyEscapesViaReturnArgument(Operand operand) {
|
||||||
|
exists(AliasFunction f |
|
||||||
|
f = operand.getUseInstruction().(CallInstruction).getStaticCallTarget() and
|
||||||
|
f.parameterEscapesOnlyViaReturn(operand.(PositionalArgumentOperand).getIndex())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isNeverEscapesArgument(Operand operand) {
|
||||||
|
exists(AliasFunction f |
|
||||||
|
f = operand.getUseInstruction().(CallInstruction).getStaticCallTarget() and
|
||||||
|
f.parameterNeverEscapes(operand.(PositionalArgumentOperand).getIndex())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate resultReturned(Instruction instr, IntValue bitOffset) {
|
||||||
|
operandReturned(instr.getAUse(), bitOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate resultMayReachReturn(Instruction instr) {
|
||||||
|
operandMayReachReturn(instr.getAUse())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if any address held in the result of instruction `instr` escapes
|
* Holds if any address held in the result of instruction `instr` escapes
|
||||||
* outside the domain of the analysis.
|
* outside the domain of the analysis.
|
||||||
*/
|
*/
|
||||||
predicate resultEscapes(Instruction instr) {
|
private predicate resultEscapesNonReturn(Instruction instr) {
|
||||||
// The result escapes if it has at least one use that escapes.
|
// The result escapes if it has at least one use that escapes.
|
||||||
operandEscapes(instr.getAUse())
|
operandEscapesNonReturn(instr.getAUse())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -169,15 +282,11 @@ predicate resultEscapes(Instruction instr) {
|
|||||||
* domain of the analysis.
|
* domain of the analysis.
|
||||||
*/
|
*/
|
||||||
private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
|
private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
|
||||||
exists(FunctionIR funcIR |
|
|
||||||
funcIR = var.getEnclosingFunctionIR() and
|
|
||||||
// The variable's address escapes if the result of any
|
// The variable's address escapes if the result of any
|
||||||
// VariableAddressInstruction that computes the variable's address escapes.
|
// VariableAddressInstruction that computes the variable's address escapes.
|
||||||
exists(VariableAddressInstruction instr |
|
exists(VariableAddressInstruction instr |
|
||||||
instr.getEnclosingFunctionIR() = funcIR and
|
|
||||||
instr.getVariable() = var and
|
instr.getVariable() = var and
|
||||||
resultEscapes(instr)
|
resultEscapesNonReturn(instr)
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +316,14 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset)
|
|||||||
// If an operand is propagated, then the result points to the same variable,
|
// If an operand is propagated, then the result points to the same variable,
|
||||||
// offset by the bit offset from the propagation.
|
// offset by the bit offset from the propagation.
|
||||||
resultPointsTo(operand.getDefinitionInstruction(), var, originalBitOffset) and
|
resultPointsTo(operand.getDefinitionInstruction(), var, originalBitOffset) and
|
||||||
operandIsPropagated(operand, propagatedBitOffset) and
|
(
|
||||||
|
operandIsPropagated(operand, propagatedBitOffset)
|
||||||
|
or
|
||||||
|
exists(CallInstruction ci, Instruction init |
|
||||||
|
isArgumentForParameter(ci, operand, init) and
|
||||||
|
resultReturned(init, propagatedBitOffset)
|
||||||
|
)
|
||||||
|
) and
|
||||||
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
|
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1310,6 +1310,13 @@ class CallInstruction extends Instruction {
|
|||||||
result = getAnOperand()
|
result = getAnOperand()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the `Function` that the call targets, if this is statically known.
|
||||||
|
*/
|
||||||
|
final Function getStaticCallTarget() {
|
||||||
|
result = getCallTarget().(FunctionInstruction).getFunctionSymbol()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all of the arguments of the call, including the `this` pointer, if any.
|
* Gets all of the arguments of the call, including the `this` pointer, if any.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1310,6 +1310,13 @@ class CallInstruction extends Instruction {
|
|||||||
result = getAnOperand()
|
result = getAnOperand()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the `Function` that the call targets, if this is statically known.
|
||||||
|
*/
|
||||||
|
final Function getStaticCallTarget() {
|
||||||
|
result = getCallTarget().(FunctionInstruction).getFunctionSymbol()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all of the arguments of the call, including the `this` pointer, if any.
|
* Gets all of the arguments of the call, including the `this` pointer, if any.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import cpp
|
|||||||
private import InputIR
|
private import InputIR
|
||||||
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||||
|
|
||||||
|
private import semmle.code.cpp.models.interfaces.Alias
|
||||||
|
|
||||||
private class IntValue = Ints::IntValue;
|
private class IntValue = Ints::IntValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,7 +48,7 @@ private IntValue getFieldBitOffset(Field field) {
|
|||||||
* not result in any address held in that operand from escaping beyond the
|
* not result in any address held in that operand from escaping beyond the
|
||||||
* instruction.
|
* instruction.
|
||||||
*/
|
*/
|
||||||
predicate operandIsConsumedWithoutEscaping(Operand operand) {
|
private predicate operandIsConsumedWithoutEscaping(Operand operand) {
|
||||||
// The source/destination address of a Load/Store does not escape (but the
|
// The source/destination address of a Load/Store does not escape (but the
|
||||||
// loaded/stored value could).
|
// loaded/stored value could).
|
||||||
operand instanceof AddressOperand or
|
operand instanceof AddressOperand or
|
||||||
@@ -60,7 +62,18 @@ predicate operandIsConsumedWithoutEscaping(Operand operand) {
|
|||||||
// Converting an address to a `bool` does not escape the address.
|
// Converting an address to a `bool` does not escape the address.
|
||||||
instr.(ConvertInstruction).getResultType() instanceof BoolType
|
instr.(ConvertInstruction).getResultType() instanceof BoolType
|
||||||
)
|
)
|
||||||
)
|
) or
|
||||||
|
// Some standard function arguments never escape
|
||||||
|
isNeverEscapesArgument(operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate operandEscapesDomain(Operand operand) {
|
||||||
|
not operandIsConsumedWithoutEscaping(operand) and
|
||||||
|
not operandIsPropagated(operand, _) and
|
||||||
|
not isArgumentForParameter(_, operand, _) and
|
||||||
|
not isOnlyEscapesViaReturnArgument(operand) and
|
||||||
|
not operand.getUseInstruction() instanceof ReturnValueInstruction and
|
||||||
|
not operand instanceof PhiOperand
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,7 +111,7 @@ IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
|
|||||||
* `bitOffset`. If the address is propagated, but the offset is not known to be
|
* `bitOffset`. If the address is propagated, but the offset is not known to be
|
||||||
* a constant, then `bitOffset` is unknown.
|
* a constant, then `bitOffset` is unknown.
|
||||||
*/
|
*/
|
||||||
predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
||||||
exists(Instruction instr |
|
exists(Instruction instr |
|
||||||
instr = operand.getUseInstruction() and
|
instr = operand.getUseInstruction() and
|
||||||
(
|
(
|
||||||
@@ -134,34 +147,134 @@ predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
|||||||
// offset of the field.
|
// offset of the field.
|
||||||
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
|
bitOffset = getFieldBitOffset(instr.(FieldAddressInstruction).getField()) or
|
||||||
// A copy propagates the source value.
|
// A copy propagates the source value.
|
||||||
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
|
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0 or
|
||||||
|
// Some functions are known to propagate an argument
|
||||||
|
isAlwaysReturnedArgument(operand) and bitOffset = 0
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private predicate operandEscapesNonReturn(Operand operand) {
|
||||||
* Holds if any address held in operand number `tag` of instruction `instr`
|
// The address is propagated to the result of the instruction, and that result itself is returned
|
||||||
* escapes outside the domain of the analysis.
|
operandIsPropagated(operand, _) and resultEscapesNonReturn(operand.getUseInstruction())
|
||||||
*/
|
or
|
||||||
predicate operandEscapes(Operand operand) {
|
// The operand is used in a function call which returns it, and the return value is then returned
|
||||||
// Conservatively assume that the address escapes unless one of the following
|
exists(CallInstruction ci, Instruction init |
|
||||||
// holds:
|
isArgumentForParameter(ci, operand, init) and
|
||||||
not (
|
(
|
||||||
// The operand is used in a way that does not escape the instruction
|
resultMayReachReturn(init) and
|
||||||
operandIsConsumedWithoutEscaping(operand) or
|
resultEscapesNonReturn(ci)
|
||||||
// The address is propagated to the result of the instruction, but that
|
or
|
||||||
// result does not itself escape.
|
resultEscapesNonReturn(init)
|
||||||
operandIsPropagated(operand, _) and not resultEscapes(operand.getUseInstruction())
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
isOnlyEscapesViaReturnArgument(operand) and resultEscapesNonReturn(operand.getUseInstruction())
|
||||||
|
or
|
||||||
|
operand instanceof PhiOperand and
|
||||||
|
resultEscapesNonReturn(operand.getUseInstruction())
|
||||||
|
or
|
||||||
|
operandEscapesDomain(operand)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate operandMayReachReturn(Operand operand) {
|
||||||
|
// The address is propagated to the result of the instruction, and that result itself is returned
|
||||||
|
operandIsPropagated(operand, _) and
|
||||||
|
resultMayReachReturn(operand.getUseInstruction())
|
||||||
|
or
|
||||||
|
// The operand is used in a function call which returns it, and the return value is then returned
|
||||||
|
exists(CallInstruction ci, Instruction init |
|
||||||
|
isArgumentForParameter(ci, operand, init) and
|
||||||
|
resultMayReachReturn(init) and
|
||||||
|
resultMayReachReturn(ci)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// The address is returned
|
||||||
|
operand.getUseInstruction() instanceof ReturnValueInstruction
|
||||||
|
or
|
||||||
|
isOnlyEscapesViaReturnArgument(operand) and resultMayReachReturn(operand.getUseInstruction())
|
||||||
|
or
|
||||||
|
operand instanceof PhiOperand and
|
||||||
|
resultMayReachReturn(operand.getUseInstruction())
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate operandReturned(Operand operand, IntValue bitOffset) {
|
||||||
|
// The address is propagated to the result of the instruction, and that result itself is returned
|
||||||
|
exists(IntValue bitOffset1, IntValue bitOffset2 |
|
||||||
|
operandIsPropagated(operand, bitOffset1) and
|
||||||
|
resultReturned(operand.getUseInstruction(), bitOffset2) and
|
||||||
|
bitOffset = Ints::add(bitOffset1, bitOffset2)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// The operand is used in a function call which returns it, and the return value is then returned
|
||||||
|
exists(CallInstruction ci, Instruction init, IntValue bitOffset1, IntValue bitOffset2 |
|
||||||
|
isArgumentForParameter(ci, operand, init) and
|
||||||
|
resultReturned(init, bitOffset1) and
|
||||||
|
resultReturned(ci, bitOffset2) and
|
||||||
|
bitOffset = Ints::add(bitOffset1, bitOffset2)
|
||||||
|
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// The address is returned
|
||||||
|
operand.getUseInstruction() instanceof ReturnValueInstruction and
|
||||||
|
bitOffset = 0
|
||||||
|
or
|
||||||
|
isOnlyEscapesViaReturnArgument(operand) and resultReturned(operand.getUseInstruction(), _) and
|
||||||
|
bitOffset = Ints::unknown()
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isArgumentForParameter(CallInstruction ci, Operand operand, Instruction init) {
|
||||||
|
exists(Function f |
|
||||||
|
ci = operand.getUseInstruction() and
|
||||||
|
f = ci.getStaticCallTarget() and
|
||||||
|
(
|
||||||
|
init.(InitializeParameterInstruction).getParameter() = f.getParameter(operand.(PositionalArgumentOperand).getIndex())
|
||||||
|
or
|
||||||
|
init instanceof InitializeThisInstruction and
|
||||||
|
init.getEnclosingFunction() = f and
|
||||||
|
operand instanceof ThisArgumentOperand
|
||||||
|
) and
|
||||||
|
not f.isVirtual() and
|
||||||
|
not f instanceof AliasFunction
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isAlwaysReturnedArgument(Operand operand) {
|
||||||
|
exists(AliasFunction f |
|
||||||
|
f = operand.getUseInstruction().(CallInstruction).getStaticCallTarget() and
|
||||||
|
f.parameterIsAlwaysReturned(operand.(PositionalArgumentOperand).getIndex())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isOnlyEscapesViaReturnArgument(Operand operand) {
|
||||||
|
exists(AliasFunction f |
|
||||||
|
f = operand.getUseInstruction().(CallInstruction).getStaticCallTarget() and
|
||||||
|
f.parameterEscapesOnlyViaReturn(operand.(PositionalArgumentOperand).getIndex())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isNeverEscapesArgument(Operand operand) {
|
||||||
|
exists(AliasFunction f |
|
||||||
|
f = operand.getUseInstruction().(CallInstruction).getStaticCallTarget() and
|
||||||
|
f.parameterNeverEscapes(operand.(PositionalArgumentOperand).getIndex())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate resultReturned(Instruction instr, IntValue bitOffset) {
|
||||||
|
operandReturned(instr.getAUse(), bitOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate resultMayReachReturn(Instruction instr) {
|
||||||
|
operandMayReachReturn(instr.getAUse())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if any address held in the result of instruction `instr` escapes
|
* Holds if any address held in the result of instruction `instr` escapes
|
||||||
* outside the domain of the analysis.
|
* outside the domain of the analysis.
|
||||||
*/
|
*/
|
||||||
predicate resultEscapes(Instruction instr) {
|
private predicate resultEscapesNonReturn(Instruction instr) {
|
||||||
// The result escapes if it has at least one use that escapes.
|
// The result escapes if it has at least one use that escapes.
|
||||||
operandEscapes(instr.getAUse())
|
operandEscapesNonReturn(instr.getAUse())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -169,15 +282,11 @@ predicate resultEscapes(Instruction instr) {
|
|||||||
* domain of the analysis.
|
* domain of the analysis.
|
||||||
*/
|
*/
|
||||||
private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
|
private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
|
||||||
exists(FunctionIR funcIR |
|
|
||||||
funcIR = var.getEnclosingFunctionIR() and
|
|
||||||
// The variable's address escapes if the result of any
|
// The variable's address escapes if the result of any
|
||||||
// VariableAddressInstruction that computes the variable's address escapes.
|
// VariableAddressInstruction that computes the variable's address escapes.
|
||||||
exists(VariableAddressInstruction instr |
|
exists(VariableAddressInstruction instr |
|
||||||
instr.getEnclosingFunctionIR() = funcIR and
|
|
||||||
instr.getVariable() = var and
|
instr.getVariable() = var and
|
||||||
resultEscapes(instr)
|
resultEscapesNonReturn(instr)
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +316,14 @@ predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset)
|
|||||||
// If an operand is propagated, then the result points to the same variable,
|
// If an operand is propagated, then the result points to the same variable,
|
||||||
// offset by the bit offset from the propagation.
|
// offset by the bit offset from the propagation.
|
||||||
resultPointsTo(operand.getDefinitionInstruction(), var, originalBitOffset) and
|
resultPointsTo(operand.getDefinitionInstruction(), var, originalBitOffset) and
|
||||||
operandIsPropagated(operand, propagatedBitOffset) and
|
(
|
||||||
|
operandIsPropagated(operand, propagatedBitOffset)
|
||||||
|
or
|
||||||
|
exists(CallInstruction ci, Instruction init |
|
||||||
|
isArgumentForParameter(ci, operand, init) and
|
||||||
|
resultReturned(init, propagatedBitOffset)
|
||||||
|
)
|
||||||
|
) and
|
||||||
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
|
bitOffset = Ints::add(originalBitOffset, propagatedBitOffset)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
| test.cpp:66:30:66:36 | test.cpp:71:8:71:9 | AST only |
|
|
||||||
| test.cpp:89:28:89:34 | test.cpp:92:8:92:14 | IR only |
|
| test.cpp:89:28:89:34 | test.cpp:92:8:92:14 | IR only |
|
||||||
| test.cpp:100:13:100:18 | test.cpp:103:10:103:12 | AST only |
|
| test.cpp:100:13:100:18 | test.cpp:103:10:103:12 | AST only |
|
||||||
| test.cpp:109:9:109:14 | test.cpp:110:10:110:12 | IR only |
|
| test.cpp:109:9:109:14 | test.cpp:110:10:110:12 | IR only |
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
| test.cpp:30:8:30:8 | Load: t | test.cpp:35:10:35:15 | Call: call to source |
|
| test.cpp:30:8:30:8 | Load: t | test.cpp:35:10:35:15 | Call: call to source |
|
||||||
| test.cpp:31:8:31:8 | Load: c | test.cpp:36:13:36:18 | Call: call to source |
|
| test.cpp:31:8:31:8 | Load: c | test.cpp:36:13:36:18 | Call: call to source |
|
||||||
| test.cpp:58:10:58:10 | Load: t | test.cpp:50:14:50:19 | Call: call to source |
|
| test.cpp:58:10:58:10 | Load: t | test.cpp:50:14:50:19 | Call: call to source |
|
||||||
|
| test.cpp:71:8:71:9 | Load: x4 | test.cpp:66:30:66:36 | InitializeParameter: source1 |
|
||||||
| test.cpp:76:8:76:9 | Load: u1 | test.cpp:75:7:75:8 | Uninitialized: definition of u1 |
|
| test.cpp:76:8:76:9 | Load: u1 | test.cpp:75:7:75:8 | Uninitialized: definition of u1 |
|
||||||
| test.cpp:84:8:84:18 | Load: ... ? ... : ... | test.cpp:83:7:83:8 | Uninitialized: definition of u2 |
|
| test.cpp:84:8:84:18 | Load: ... ? ... : ... | test.cpp:83:7:83:8 | Uninitialized: definition of u2 |
|
||||||
| test.cpp:86:8:86:9 | Load: i1 | test.cpp:83:7:83:8 | Uninitialized: definition of u2 |
|
| test.cpp:86:8:86:9 | Load: i1 | test.cpp:83:7:83:8 | Uninitialized: definition of u2 |
|
||||||
|
|||||||
@@ -1,5 +1,44 @@
|
|||||||
void CallByPointer(int* p);
|
void CallByPointer(int* p);
|
||||||
void CallByReference(int& r);
|
void CallByReference(int& r);
|
||||||
|
int *GetPointer();
|
||||||
|
int &GetReference();
|
||||||
|
|
||||||
|
int FetchFromPointer(int *no_p) {
|
||||||
|
return *no_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FetchFromReference(int &no_r) {
|
||||||
|
return no_r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int *ReturnPointer(int *no_p) {
|
||||||
|
return no_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int &ReturnReference(int &no_r) {
|
||||||
|
return no_r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallByPointerParamEscape(int *no_p) {
|
||||||
|
CallByPointer(no_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallByReferenceParamEscape(int &no_r) {
|
||||||
|
CallByReference(no_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int *MaybeReturn(int *no_p, int *no_q, bool no_b) {
|
||||||
|
if (no_b) {
|
||||||
|
return no_p;
|
||||||
|
} else {
|
||||||
|
return no_q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int &EscapeAndReturn(int &no_r) {
|
||||||
|
CallByReference(no_r);
|
||||||
|
return no_r;
|
||||||
|
}
|
||||||
|
|
||||||
struct Point {
|
struct Point {
|
||||||
float x;
|
float x;
|
||||||
@@ -27,6 +66,40 @@ struct Derived : Intermediate1, Intermediate2 {
|
|||||||
float d;
|
float d;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class C;
|
||||||
|
|
||||||
|
void CEscapes(C *no_c);
|
||||||
|
|
||||||
|
class C {
|
||||||
|
public:
|
||||||
|
void ThisEscapes() {
|
||||||
|
CEscapes(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
C *ThisReturned() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual C *Overridden() {
|
||||||
|
CEscapes(this);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OverrideReturns : C {
|
||||||
|
public:
|
||||||
|
virtual C *Overridden() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OverrideNone : C {
|
||||||
|
public:
|
||||||
|
virtual C *Overridden() {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void Escape()
|
void Escape()
|
||||||
{
|
{
|
||||||
int no_result;
|
int no_result;
|
||||||
@@ -95,4 +168,86 @@ void Escape()
|
|||||||
|
|
||||||
int passByRef;
|
int passByRef;
|
||||||
CallByReference(passByRef);
|
CallByReference(passByRef);
|
||||||
|
|
||||||
|
int no_ssa_passByPtr;
|
||||||
|
FetchFromPointer(&no_ssa_passByPtr);
|
||||||
|
|
||||||
|
int no_ssa_passByRef;
|
||||||
|
FetchFromReference(no_ssa_passByRef);
|
||||||
|
|
||||||
|
int no_ssa_passByPtr_ret;
|
||||||
|
FetchFromPointer(&no_ssa_passByPtr_ret);
|
||||||
|
|
||||||
|
int no_ssa_passByRef_ret;
|
||||||
|
FetchFromReference(no_ssa_passByRef_ret);
|
||||||
|
|
||||||
|
int passByPtr2;
|
||||||
|
CallByPointerParamEscape(&passByPtr2);
|
||||||
|
|
||||||
|
int passByRef2;
|
||||||
|
CallByReferenceParamEscape(passByRef2);
|
||||||
|
|
||||||
|
int passByPtr3;
|
||||||
|
CallByPointerParamEscape(ReturnPointer(&passByPtr3));
|
||||||
|
|
||||||
|
int passByRef3;
|
||||||
|
CallByReferenceParamEscape(ReturnReference(passByRef3));
|
||||||
|
|
||||||
|
int no_ssa_passByPtr4;
|
||||||
|
int no_ssa_passByPtr5;
|
||||||
|
bool no_b2 = false;
|
||||||
|
MaybeReturn(&no_ssa_passByPtr4, &no_ssa_passByPtr5, no_b2);
|
||||||
|
|
||||||
|
int passByRef6;
|
||||||
|
EscapeAndReturn(passByRef6);
|
||||||
|
|
||||||
|
int no_ssa_passByRef7;
|
||||||
|
ReturnReference(no_ssa_passByRef7);
|
||||||
|
|
||||||
|
C no_ssa_c;
|
||||||
|
|
||||||
|
no_ssa_c.ThisReturned();
|
||||||
|
|
||||||
|
C c;
|
||||||
|
|
||||||
|
c.ThisEscapes();
|
||||||
|
|
||||||
|
C c2;
|
||||||
|
|
||||||
|
CEscapes(&c2);
|
||||||
|
|
||||||
|
C c3;
|
||||||
|
|
||||||
|
c3.ThisReturned()->ThisEscapes();
|
||||||
|
|
||||||
|
C c4;
|
||||||
|
|
||||||
|
CEscapes(c4.ThisReturned());
|
||||||
|
|
||||||
|
C c5;
|
||||||
|
|
||||||
|
c5.Overridden();
|
||||||
|
|
||||||
|
OverrideReturns or1;
|
||||||
|
or1.Overridden();
|
||||||
|
|
||||||
|
OverrideReturns or2;
|
||||||
|
CEscapes(or2.Overridden());
|
||||||
|
|
||||||
|
OverrideNone on1;
|
||||||
|
on1.Overridden();
|
||||||
|
|
||||||
|
OverrideNone on2;
|
||||||
|
CEscapes(on2.Overridden());
|
||||||
|
|
||||||
|
int condEscape1, condEscape2;
|
||||||
|
|
||||||
|
int *no_condTemp;
|
||||||
|
if(GetPointer()) {
|
||||||
|
no_condTemp = &condEscape1;
|
||||||
|
} else {
|
||||||
|
no_condTemp = &condEscape2;
|
||||||
|
}
|
||||||
|
CallByPointer(no_condTemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,108 +1,47 @@
|
|||||||
| escape.cpp:32:9:32:17 | VariableAddress[no_result] | no_result+0:0 |
|
| escape.cpp:115:19:115:28 | PointerAdd[4] | no_+0:0 | no_+0:0 |
|
||||||
| escape.cpp:33:9:33:11 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:116:19:116:28 | PointerSub[4] | no_+0:0 | no_+0:0 |
|
||||||
| escape.cpp:35:5:35:7 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:117:19:117:26 | PointerAdd[4] | no_+0:0 | no_+0:0 |
|
||||||
| escape.cpp:36:5:36:7 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:134:5:134:18 | Convert | no_Array+0:0 | no_Array+0:0 |
|
||||||
| escape.cpp:36:11:36:13 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:134:11:134:18 | Convert | no_Array+0:0 | no_Array+0:0 |
|
||||||
| escape.cpp:37:5:37:13 | VariableAddress[no_result] | no_result+0:0 |
|
| escape.cpp:135:5:135:12 | Convert | no_Array+0:0 | no_Array+0:0 |
|
||||||
| escape.cpp:37:17:37:19 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:135:5:135:15 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 |
|
||||||
| escape.cpp:38:5:38:13 | VariableAddress[no_result] | no_result+0:0 |
|
| escape.cpp:136:5:136:15 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 |
|
||||||
| escape.cpp:38:19:38:21 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:136:7:136:14 | Convert | no_Array+0:0 | no_Array+0:0 |
|
||||||
| escape.cpp:40:5:40:7 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:137:17:137:24 | Convert | no_Array+0:0 | no_Array+0:0 |
|
||||||
| escape.cpp:41:6:41:8 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:137:17:137:27 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 |
|
||||||
| escape.cpp:42:5:42:13 | VariableAddress[no_result] | no_result+0:0 |
|
| escape.cpp:138:17:138:27 | PointerAdd[4] | no_Array+20:0 | no_Array+20:0 |
|
||||||
| escape.cpp:42:19:42:28 | PointerAdd[4] | no_+0:0 |
|
| escape.cpp:138:19:138:26 | Convert | no_Array+0:0 | no_Array+0:0 |
|
||||||
| escape.cpp:42:21:42:23 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:140:21:140:32 | FieldAddress[x] | no_Point+0:0 | no_Point+0:0 |
|
||||||
| escape.cpp:43:5:43:13 | VariableAddress[no_result] | no_result+0:0 |
|
| escape.cpp:140:21:140:32 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
|
||||||
| escape.cpp:43:19:43:28 | PointerSub[4] | no_+0:0 |
|
| escape.cpp:140:21:140:32 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 |
|
||||||
| escape.cpp:43:21:43:23 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:141:27:141:27 | FieldAddress[x] | no_Point+0:0 | no_Point+0:0 |
|
||||||
| escape.cpp:44:5:44:13 | VariableAddress[no_result] | no_result+0:0 |
|
| escape.cpp:142:14:142:14 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
|
||||||
| escape.cpp:44:19:44:26 | PointerAdd[4] | no_+0:0 |
|
| escape.cpp:143:31:143:31 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
|
||||||
| escape.cpp:44:24:44:26 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:144:18:144:18 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
|
||||||
| escape.cpp:45:10:45:12 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:145:30:145:30 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 |
|
||||||
| escape.cpp:47:13:47:15 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:146:17:146:17 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 |
|
||||||
| escape.cpp:50:15:50:17 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:149:5:149:14 | ConvertToBase[Derived : Intermediate1] | no_Derived+0:0 | no_Derived+0:0 |
|
||||||
| escape.cpp:51:10:51:12 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:149:5:149:14 | ConvertToBase[Intermediate1 : Base] | no_Derived+0:0 | no_Derived+0:0 |
|
||||||
| escape.cpp:51:16:51:18 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:149:16:149:16 | FieldAddress[b] | no_Derived+0:0 | no_Derived+0:0 |
|
||||||
| escape.cpp:51:22:51:24 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:150:18:150:27 | ConvertToBase[Derived : Intermediate1] | no_Derived+0:0 | no_Derived+0:0 |
|
||||||
| escape.cpp:54:10:54:12 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:150:18:150:27 | ConvertToBase[Intermediate1 : Base] | no_Derived+0:0 | no_Derived+0:0 |
|
||||||
| escape.cpp:56:13:56:15 | VariableAddress[no_] | no_+0:0 |
|
| escape.cpp:150:29:150:29 | FieldAddress[b] | no_Derived+0:0 | no_Derived+0:0 |
|
||||||
| escape.cpp:59:9:59:16 | VariableAddress[no_Array] | no_Array+0:0 |
|
| escape.cpp:151:5:151:14 | ConvertToBase[Derived : Intermediate2] | no_Derived+12:0 | no_Derived+12:0 |
|
||||||
| escape.cpp:60:5:60:12 | VariableAddress[no_Array] | no_Array+0:0 |
|
| escape.cpp:151:16:151:17 | FieldAddress[i2] | no_Derived+16:0 | no_Derived+16:0 |
|
||||||
| escape.cpp:61:5:61:18 | Convert | no_Array+0:0 |
|
| escape.cpp:152:19:152:28 | ConvertToBase[Derived : Intermediate2] | no_Derived+12:0 | no_Derived+12:0 |
|
||||||
| escape.cpp:61:11:61:18 | Convert | no_Array+0:0 |
|
| escape.cpp:152:30:152:31 | FieldAddress[i2] | no_Derived+16:0 | no_Derived+16:0 |
|
||||||
| escape.cpp:61:11:61:18 | VariableAddress[no_Array] | no_Array+0:0 |
|
| escape.cpp:155:17:155:30 | Store | no_ssa_addrOf+0:0 | no_ssa_addrOf+0:0 |
|
||||||
| escape.cpp:62:5:62:12 | Convert | no_Array+0:0 |
|
| escape.cpp:158:17:158:28 | Store | no_ssa_refTo+0:0 | no_ssa_refTo+0:0 |
|
||||||
| escape.cpp:62:5:62:12 | VariableAddress[no_Array] | no_Array+0:0 |
|
| escape.cpp:161:19:161:42 | Convert | no_ssa_refToArrayElement+0:0 | no_ssa_refToArrayElement+0:0 |
|
||||||
| escape.cpp:62:5:62:15 | PointerAdd[4] | no_Array+20:0 |
|
| escape.cpp:161:19:161:45 | PointerAdd[4] | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 |
|
||||||
| escape.cpp:63:5:63:15 | PointerAdd[4] | no_Array+20:0 |
|
| escape.cpp:161:19:161:45 | Store | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 |
|
||||||
| escape.cpp:63:7:63:14 | Convert | no_Array+0:0 |
|
| escape.cpp:164:24:164:40 | Store | no_ssa_refToArray+0:0 | no_ssa_refToArray+0:0 |
|
||||||
| escape.cpp:63:7:63:14 | VariableAddress[no_Array] | no_Array+0:0 |
|
| escape.cpp:191:30:191:42 | Call | none | passByPtr3+0:0 |
|
||||||
| escape.cpp:64:5:64:13 | VariableAddress[no_result] | no_result+0:0 |
|
| escape.cpp:194:32:194:46 | Call | none | passByRef3+0:0 |
|
||||||
| escape.cpp:64:17:64:24 | Convert | no_Array+0:0 |
|
| escape.cpp:202:5:202:19 | Call | none | passByRef6+0:0 |
|
||||||
| escape.cpp:64:17:64:24 | VariableAddress[no_Array] | no_Array+0:0 |
|
| escape.cpp:205:5:205:19 | Call | none | no_ssa_passByRef7+0:0 |
|
||||||
| escape.cpp:64:17:64:27 | PointerAdd[4] | no_Array+20:0 |
|
| escape.cpp:209:14:209:25 | Call | none | no_ssa_c+0:0 |
|
||||||
| escape.cpp:65:5:65:13 | VariableAddress[no_result] | no_result+0:0 |
|
| escape.cpp:221:8:221:19 | Call | none | c3+0:0 |
|
||||||
| escape.cpp:65:17:65:27 | PointerAdd[4] | no_Array+20:0 |
|
| escape.cpp:225:17:225:28 | Call | none | c4+0:0 |
|
||||||
| escape.cpp:65:19:65:26 | Convert | no_Array+0:0 |
|
| escape.cpp:247:2:247:27 | Store | condEscape1+0:0 | condEscape1+0:0 |
|
||||||
| escape.cpp:65:19:65:26 | VariableAddress[no_Array] | no_Array+0:0 |
|
| escape.cpp:249:9:249:34 | Store | condEscape2+0:0 | condEscape2+0:0 |
|
||||||
| escape.cpp:67:11:67:18 | VariableAddress[no_Point] | no_Point+0:0 |
|
|
||||||
| escape.cpp:67:21:67:32 | FieldAddress[x] | no_Point+0:0 |
|
|
||||||
| escape.cpp:67:21:67:32 | FieldAddress[y] | no_Point+4:0 |
|
|
||||||
| escape.cpp:67:21:67:32 | FieldAddress[z] | no_Point+8:0 |
|
|
||||||
| escape.cpp:68:11:68:14 | VariableAddress[no_x] | no_x+0:0 |
|
|
||||||
| escape.cpp:68:18:68:25 | VariableAddress[no_Point] | no_Point+0:0 |
|
|
||||||
| escape.cpp:68:27:68:27 | FieldAddress[x] | no_Point+0:0 |
|
|
||||||
| escape.cpp:69:5:69:12 | VariableAddress[no_Point] | no_Point+0:0 |
|
|
||||||
| escape.cpp:69:14:69:14 | FieldAddress[y] | no_Point+4:0 |
|
|
||||||
| escape.cpp:69:18:69:21 | VariableAddress[no_x] | no_x+0:0 |
|
|
||||||
| escape.cpp:70:11:70:14 | VariableAddress[no_y] | no_y+0:0 |
|
|
||||||
| escape.cpp:70:20:70:27 | VariableAddress[no_Point] | no_Point+0:0 |
|
|
||||||
| escape.cpp:70:31:70:31 | FieldAddress[y] | no_Point+4:0 |
|
|
||||||
| escape.cpp:71:7:71:14 | VariableAddress[no_Point] | no_Point+0:0 |
|
|
||||||
| escape.cpp:71:18:71:18 | FieldAddress[y] | no_Point+4:0 |
|
|
||||||
| escape.cpp:71:22:71:25 | VariableAddress[no_y] | no_y+0:0 |
|
|
||||||
| escape.cpp:72:11:72:14 | VariableAddress[no_z] | no_z+0:0 |
|
|
||||||
| escape.cpp:72:21:72:28 | VariableAddress[no_Point] | no_Point+0:0 |
|
|
||||||
| escape.cpp:72:30:72:30 | FieldAddress[z] | no_Point+8:0 |
|
|
||||||
| escape.cpp:73:8:73:15 | VariableAddress[no_Point] | no_Point+0:0 |
|
|
||||||
| escape.cpp:73:17:73:17 | FieldAddress[z] | no_Point+8:0 |
|
|
||||||
| escape.cpp:73:22:73:25 | VariableAddress[no_z] | no_z+0:0 |
|
|
||||||
| escape.cpp:75:13:75:22 | VariableAddress[no_Derived] | no_Derived+0:0 |
|
|
||||||
| escape.cpp:76:5:76:14 | ConvertToBase[Derived : Intermediate1] | no_Derived+0:0 |
|
|
||||||
| escape.cpp:76:5:76:14 | ConvertToBase[Intermediate1 : Base] | no_Derived+0:0 |
|
|
||||||
| escape.cpp:76:5:76:14 | VariableAddress[no_Derived] | no_Derived+0:0 |
|
|
||||||
| escape.cpp:76:16:76:16 | FieldAddress[b] | no_Derived+0:0 |
|
|
||||||
| escape.cpp:77:11:77:14 | VariableAddress[no_b] | no_b+0:0 |
|
|
||||||
| escape.cpp:77:18:77:27 | ConvertToBase[Derived : Intermediate1] | no_Derived+0:0 |
|
|
||||||
| escape.cpp:77:18:77:27 | ConvertToBase[Intermediate1 : Base] | no_Derived+0:0 |
|
|
||||||
| escape.cpp:77:18:77:27 | VariableAddress[no_Derived] | no_Derived+0:0 |
|
|
||||||
| escape.cpp:77:29:77:29 | FieldAddress[b] | no_Derived+0:0 |
|
|
||||||
| escape.cpp:78:5:78:14 | ConvertToBase[Derived : Intermediate2] | no_Derived+12:0 |
|
|
||||||
| escape.cpp:78:5:78:14 | VariableAddress[no_Derived] | no_Derived+0:0 |
|
|
||||||
| escape.cpp:78:16:78:17 | FieldAddress[i2] | no_Derived+16:0 |
|
|
||||||
| escape.cpp:79:11:79:15 | VariableAddress[no_i2] | no_i2+0:0 |
|
|
||||||
| escape.cpp:79:19:79:28 | ConvertToBase[Derived : Intermediate2] | no_Derived+12:0 |
|
|
||||||
| escape.cpp:79:19:79:28 | VariableAddress[no_Derived] | no_Derived+0:0 |
|
|
||||||
| escape.cpp:79:30:79:31 | FieldAddress[i2] | no_Derived+16:0 |
|
|
||||||
| escape.cpp:81:9:81:21 | VariableAddress[no_ssa_addrOf] | no_ssa_addrOf+0:0 |
|
|
||||||
| escape.cpp:82:10:82:13 | VariableAddress[no_p] | no_p+0:0 |
|
|
||||||
| escape.cpp:82:17:82:30 | Store | no_ssa_addrOf+0:0 |
|
|
||||||
| escape.cpp:82:18:82:30 | VariableAddress[no_ssa_addrOf] | no_ssa_addrOf+0:0 |
|
|
||||||
| escape.cpp:84:9:84:20 | VariableAddress[no_ssa_refTo] | no_ssa_refTo+0:0 |
|
|
||||||
| escape.cpp:85:10:85:13 | VariableAddress[no_r] | no_r+0:0 |
|
|
||||||
| escape.cpp:85:17:85:28 | Store | no_ssa_refTo+0:0 |
|
|
||||||
| escape.cpp:85:17:85:28 | VariableAddress[no_ssa_refTo] | no_ssa_refTo+0:0 |
|
|
||||||
| escape.cpp:87:9:87:32 | VariableAddress[no_ssa_refToArrayElement] | no_ssa_refToArrayElement+0:0 |
|
|
||||||
| escape.cpp:88:10:88:15 | VariableAddress[no_rae] | no_rae+0:0 |
|
|
||||||
| escape.cpp:88:19:88:42 | Convert | no_ssa_refToArrayElement+0:0 |
|
|
||||||
| escape.cpp:88:19:88:42 | VariableAddress[no_ssa_refToArrayElement] | no_ssa_refToArrayElement+0:0 |
|
|
||||||
| escape.cpp:88:19:88:45 | PointerAdd[4] | no_ssa_refToArrayElement+20:0 |
|
|
||||||
| escape.cpp:88:19:88:45 | Store | no_ssa_refToArrayElement+20:0 |
|
|
||||||
| escape.cpp:90:9:90:25 | VariableAddress[no_ssa_refToArray] | no_ssa_refToArray+0:0 |
|
|
||||||
| escape.cpp:91:11:91:15 | VariableAddress[no_ra] | no_ra+0:0 |
|
|
||||||
| escape.cpp:91:24:91:40 | Store | no_ssa_refToArray+0:0 |
|
|
||||||
| escape.cpp:91:24:91:40 | VariableAddress[no_ssa_refToArray] | no_ssa_refToArray+0:0 |
|
|
||||||
| escape.cpp:93:9:93:17 | VariableAddress[passByPtr] | passByPtr+0:0 |
|
|
||||||
| escape.cpp:94:20:94:28 | VariableAddress[passByPtr] | passByPtr+0:0 |
|
|
||||||
| escape.cpp:96:9:96:17 | VariableAddress[passByRef] | passByRef+0:0 |
|
|
||||||
| escape.cpp:97:21:97:29 | VariableAddress[passByRef] | passByRef+0:0 |
|
|
||||||
|
|||||||
@@ -1,11 +1,34 @@
|
|||||||
import default
|
import default
|
||||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.AliasAnalysis
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.AliasAnalysis as RawAA
|
||||||
import semmle.code.cpp.ir.implementation.raw.IR
|
import semmle.code.cpp.ir.implementation.raw.IR as Raw
|
||||||
|
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.AliasAnalysis as UnAA
|
||||||
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as Un
|
||||||
|
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction
|
||||||
|
|
||||||
from Instruction instr, string pointsTo
|
from Raw::Instruction rawInstr, Un::Instruction unInstr, string rawPointsTo, string unPointsTo
|
||||||
where
|
where
|
||||||
exists(IRVariable var, int bitOffset |
|
rawInstr = getOldInstruction(unInstr) and
|
||||||
resultPointsTo(instr, var, bitOffset) and
|
not rawInstr instanceof Raw::VariableAddressInstruction and
|
||||||
pointsTo = var.toString() + getBitOffsetString(bitOffset)
|
(
|
||||||
|
exists(Variable var, int rawBitOffset, int unBitOffset |
|
||||||
|
RawAA::resultPointsTo(rawInstr, Raw::getIRUserVariable(_, var), rawBitOffset) and
|
||||||
|
rawPointsTo = var.toString() + RawAA::getBitOffsetString(rawBitOffset) and
|
||||||
|
UnAA::resultPointsTo(unInstr, Un::getIRUserVariable(_, var), unBitOffset) and
|
||||||
|
unPointsTo = var.toString() + UnAA::getBitOffsetString(unBitOffset)
|
||||||
)
|
)
|
||||||
select instr.getLocation().toString(), instr.getOperationString(), pointsTo
|
or
|
||||||
|
exists(Variable var, int unBitOffset |
|
||||||
|
not RawAA::resultPointsTo(rawInstr, Raw::getIRUserVariable(_, var), _) and
|
||||||
|
rawPointsTo = "none" and
|
||||||
|
UnAA::resultPointsTo(unInstr, Un::getIRUserVariable(_, var), unBitOffset) and
|
||||||
|
unPointsTo = var.toString() + UnAA::getBitOffsetString(unBitOffset)
|
||||||
|
)
|
||||||
|
or
|
||||||
|
exists(Variable var, int rawBitOffset |
|
||||||
|
RawAA::resultPointsTo(rawInstr, Raw::getIRUserVariable(_, var), rawBitOffset) and
|
||||||
|
rawPointsTo = var.toString() + RawAA::getBitOffsetString(rawBitOffset) and
|
||||||
|
not UnAA::resultPointsTo(unInstr, Un::getIRUserVariable(_, var), _) and
|
||||||
|
unPointsTo = "none"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
select rawInstr.getLocation().toString(), rawInstr.getOperationString(), rawPointsTo, unPointsTo
|
||||||
|
|||||||
Reference in New Issue
Block a user