Merge pull request #792 from rdmarsh2/rdmarsh/cpp/escape-analysis

C++: Interprocedural escape/alias analysis in IR construction
This commit is contained in:
Jonas Jensen
2019-03-08 07:29:26 +01:00
committed by GitHub
10 changed files with 544 additions and 174 deletions

View File

@@ -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.
*/ */

View File

@@ -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)
) )
} }

View File

@@ -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.
*/ */

View File

@@ -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.
*/ */

View File

@@ -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)
) )
} }

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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);
}

View File

@@ -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 |

View File

@@ -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