mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Merge pull request #5737 from dbartol/dbartol/smart-pointers/work
C++: IR Alias Analysis for smart pointers
This commit is contained in:
@@ -694,7 +694,12 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) {
|
||||
fromExpr = call.getQualifier()
|
||||
) and
|
||||
call.getTarget() = f and
|
||||
outModel.isReturnValue()
|
||||
// AST dataflow treats a reference as if it were the referred-to object, while the dataflow
|
||||
// models treat references as pointers. If the return type of the call is a reference, then
|
||||
// look for data flow the the referred-to object, rather than the reference itself.
|
||||
if call.getType().getUnspecifiedType() instanceof ReferenceType
|
||||
then outModel.isReturnValueDeref()
|
||||
else outModel.isReturnValue()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1645,6 +1645,19 @@ class CallInstruction extends Instruction {
|
||||
* Gets the number of arguments of the call, including the `this` pointer, if any.
|
||||
*/
|
||||
final int getNumberOfArguments() { result = count(this.getAnArgumentOperand()) }
|
||||
|
||||
/**
|
||||
* Holds if the result is a side effect for the argument at the specified index, or `this` if
|
||||
* `index` is `-1`.
|
||||
*
|
||||
* This helper predicate makes it easy to join on both of these columns at once, avoiding
|
||||
* pathological join orders in case the argument index should get joined first.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final SideEffectInstruction getAParameterSideEffect(int index) {
|
||||
this = result.getPrimaryInstruction() and
|
||||
index = result.(IndexedInstruction).getIndex()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,71 @@ private import AliasAnalysisImports
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
|
||||
/**
|
||||
* If `instr` is a `SideEffectInstruction`, gets the primary `CallInstruction` that caused the side
|
||||
* effect. If `instr` is a `CallInstruction`, gets that same `CallInstruction`.
|
||||
*/
|
||||
private CallInstruction getPrimaryCall(Instruction instr) {
|
||||
result = instr
|
||||
or
|
||||
result = instr.(SideEffectInstruction).getPrimaryInstruction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operand` serves as an input argument (or indirection) to `call`, in the position
|
||||
* specified by `input`.
|
||||
*/
|
||||
private predicate isCallInput(
|
||||
CallInstruction call, Operand operand, AliasModels::FunctionInput input
|
||||
) {
|
||||
call = getPrimaryCall(operand.getUse()) and
|
||||
(
|
||||
exists(int index |
|
||||
input.isParameterOrQualifierAddress(index) and
|
||||
operand = call.getArgumentOperand(index)
|
||||
)
|
||||
or
|
||||
exists(int index, ReadSideEffectInstruction read |
|
||||
input.isParameterDerefOrQualifierObject(index) and
|
||||
read = call.getAParameterSideEffect(index) and
|
||||
operand = read.getSideEffectOperand()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` serves as a return value or output argument indirection for `call`, in the
|
||||
* position specified by `output`.
|
||||
*/
|
||||
private predicate isCallOutput(
|
||||
CallInstruction call, Instruction instr, AliasModels::FunctionOutput output
|
||||
) {
|
||||
call = getPrimaryCall(instr) and
|
||||
(
|
||||
output.isReturnValue() and instr = call
|
||||
or
|
||||
exists(int index, WriteSideEffectInstruction write |
|
||||
output.isParameterDerefOrQualifierObject(index) and
|
||||
write = call.getAParameterSideEffect(index) and
|
||||
instr = write
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address in `operand` flows directly to the result of `resultInstr` due to modeled
|
||||
* address flow through a function call.
|
||||
*/
|
||||
private predicate hasAddressFlowThroughCall(Operand operand, Instruction resultInstr) {
|
||||
exists(
|
||||
CallInstruction call, AliasModels::FunctionInput input, AliasModels::FunctionOutput output
|
||||
|
|
||||
call.getStaticCallTarget().(AliasModels::AliasFunction).hasAddressFlow(input, output) and
|
||||
isCallInput(call, operand, input) and
|
||||
isCallOutput(call, resultInstr, output)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the operand `tag` of instruction `instr` is used in a way that does
|
||||
* not result in any address held in that operand from escaping beyond the
|
||||
@@ -34,7 +99,7 @@ private predicate operandIsConsumedWithoutEscaping(Operand operand) {
|
||||
|
||||
private predicate operandEscapesDomain(Operand operand) {
|
||||
not operandIsConsumedWithoutEscaping(operand) and
|
||||
not operandIsPropagated(operand, _) and
|
||||
not operandIsPropagated(operand, _, _) and
|
||||
not isArgumentForParameter(_, operand, _) and
|
||||
not isOnlyEscapesViaReturnArgument(operand) and
|
||||
not operand.getUse() instanceof ReturnValueInstruction and
|
||||
@@ -69,67 +134,67 @@ IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in operand `tag` of instruction `instr` is
|
||||
* propagated to the result of `instr`, offset by the number of bits in
|
||||
* `bitOffset`. If the address is propagated, but the offset is not known to be
|
||||
* a constant, then `bitOffset` is unknown.
|
||||
* Holds if any address held in operand `operand` is propagated to the result of `instr`, offset by
|
||||
* the number of bits in `bitOffset`. If the address is propagated, but the offset is not known to
|
||||
* be a constant, then `bitOffset` is `unknown()`.
|
||||
*/
|
||||
private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
||||
exists(Instruction instr |
|
||||
instr = operand.getUse() and
|
||||
(
|
||||
// Converting to a non-virtual base class adds the offset of the base class.
|
||||
exists(ConvertToNonVirtualBaseInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
)
|
||||
or
|
||||
// Conversion using dynamic_cast results in an unknown offset
|
||||
instr instanceof CheckedConvertOrNullInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
|
||||
)
|
||||
or
|
||||
// Converting to a virtual base class adds an unknown offset.
|
||||
instr instanceof ConvertToVirtualBaseInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
or
|
||||
// Conversion to another pointer type propagates the source address.
|
||||
exists(ConvertInstruction convert, IRType resultType |
|
||||
convert = instr and
|
||||
resultType = convert.getResultIRType() and
|
||||
resultType instanceof IRAddressType and
|
||||
bitOffset = 0
|
||||
)
|
||||
or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
exists(PointerOffsetInstruction ptrOffset |
|
||||
ptrOffset = instr and
|
||||
operand = ptrOffset.getLeftOperand() and
|
||||
bitOffset = getPointerBitOffset(ptrOffset)
|
||||
)
|
||||
or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
bitOffset = Language::getFieldBitOffset(instr.(FieldAddressInstruction).getField())
|
||||
or
|
||||
// A copy propagates the source value.
|
||||
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
|
||||
or
|
||||
// Some functions are known to propagate an argument
|
||||
isAlwaysReturnedArgument(operand) and bitOffset = 0
|
||||
private predicate operandIsPropagated(Operand operand, IntValue bitOffset, Instruction instr) {
|
||||
// Some functions are known to propagate an argument
|
||||
hasAddressFlowThroughCall(operand, instr) and
|
||||
bitOffset = 0
|
||||
or
|
||||
instr = operand.getUse() and
|
||||
(
|
||||
// Converting to a non-virtual base class adds the offset of the base class.
|
||||
exists(ConvertToNonVirtualBaseInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
)
|
||||
or
|
||||
// Conversion using dynamic_cast results in an unknown offset
|
||||
instr instanceof CheckedConvertOrNullInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
|
||||
)
|
||||
or
|
||||
// Converting to a virtual base class adds an unknown offset.
|
||||
instr instanceof ConvertToVirtualBaseInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
or
|
||||
// Conversion to another pointer type propagates the source address.
|
||||
exists(ConvertInstruction convert, IRType resultType |
|
||||
convert = instr and
|
||||
resultType = convert.getResultIRType() and
|
||||
resultType instanceof IRAddressType and
|
||||
bitOffset = 0
|
||||
)
|
||||
or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
exists(PointerOffsetInstruction ptrOffset |
|
||||
ptrOffset = instr and
|
||||
operand = ptrOffset.getLeftOperand() and
|
||||
bitOffset = getPointerBitOffset(ptrOffset)
|
||||
)
|
||||
or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
bitOffset = Language::getFieldBitOffset(instr.(FieldAddressInstruction).getField())
|
||||
or
|
||||
// A copy propagates the source value.
|
||||
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
|
||||
)
|
||||
}
|
||||
|
||||
private predicate operandEscapesNonReturn(Operand operand) {
|
||||
// The address is propagated to the result of the instruction, and that result itself is returned
|
||||
operandIsPropagated(operand, _) and resultEscapesNonReturn(operand.getUse())
|
||||
exists(Instruction instr |
|
||||
// The address is propagated to the result of the instruction, and that result itself is returned
|
||||
operandIsPropagated(operand, _, instr) and resultEscapesNonReturn(instr)
|
||||
)
|
||||
or
|
||||
// The operand is used in a function call which returns it, and the return value is then returned
|
||||
exists(CallInstruction ci, Instruction init |
|
||||
@@ -151,9 +216,11 @@ private predicate operandEscapesNonReturn(Operand 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.getUse())
|
||||
exists(Instruction instr |
|
||||
// The address is propagated to the result of the instruction, and that result itself is returned
|
||||
operandIsPropagated(operand, _, instr) and
|
||||
resultMayReachReturn(instr)
|
||||
)
|
||||
or
|
||||
// The operand is used in a function call which returns it, and the return value is then returned
|
||||
exists(CallInstruction ci, Instruction init |
|
||||
@@ -173,9 +240,9 @@ private predicate operandMayReachReturn(Operand operand) {
|
||||
|
||||
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.getUse(), bitOffset2) and
|
||||
exists(Instruction instr, IntValue bitOffset1, IntValue bitOffset2 |
|
||||
operandIsPropagated(operand, bitOffset1, instr) and
|
||||
resultReturned(instr, bitOffset2) and
|
||||
bitOffset = Ints::add(bitOffset1, bitOffset2)
|
||||
)
|
||||
or
|
||||
@@ -214,13 +281,6 @@ private predicate isArgumentForParameter(
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isAlwaysReturnedArgument(Operand operand) {
|
||||
exists(AliasModels::AliasFunction f |
|
||||
f = operand.getUse().(CallInstruction).getStaticCallTarget() and
|
||||
f.parameterIsAlwaysReturned(operand.(PositionalArgumentOperand).getIndex())
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isOnlyEscapesViaReturnArgument(Operand operand) {
|
||||
exists(AliasModels::AliasFunction f |
|
||||
f = operand.getUse().(CallInstruction).getStaticCallTarget() and
|
||||
@@ -270,12 +330,15 @@ predicate allocationEscapes(Configuration::Allocation allocation) {
|
||||
/**
|
||||
* Equivalent to `operandIsPropagated()`, but includes interprocedural propagation.
|
||||
*/
|
||||
private predicate operandIsPropagatedIncludingByCall(Operand operand, IntValue bitOffset) {
|
||||
operandIsPropagated(operand, bitOffset)
|
||||
private predicate operandIsPropagatedIncludingByCall(
|
||||
Operand operand, IntValue bitOffset, Instruction instr
|
||||
) {
|
||||
operandIsPropagated(operand, bitOffset, instr)
|
||||
or
|
||||
exists(CallInstruction call, Instruction init |
|
||||
isArgumentForParameter(call, operand, init) and
|
||||
resultReturned(init, bitOffset)
|
||||
resultReturned(init, bitOffset) and
|
||||
instr = call
|
||||
)
|
||||
}
|
||||
|
||||
@@ -292,8 +355,7 @@ private predicate hasBaseAndOffset(AddressOperand addrOperand, Instruction base,
|
||||
// We already have an offset from `middle`.
|
||||
hasBaseAndOffset(addrOperand, middle, previousBitOffset) and
|
||||
// `middle` is propagated from `base`.
|
||||
middleOperand = middle.getAnOperand() and
|
||||
operandIsPropagatedIncludingByCall(middleOperand, additionalBitOffset) and
|
||||
operandIsPropagatedIncludingByCall(middleOperand, additionalBitOffset, middle) and
|
||||
base = middleOperand.getDef() and
|
||||
bitOffset = Ints::add(previousBitOffset, additionalBitOffset)
|
||||
)
|
||||
|
||||
@@ -105,7 +105,21 @@ class DynamicAllocation extends Allocation, TDynamicAllocation {
|
||||
DynamicAllocation() { this = TDynamicAllocation(call) }
|
||||
|
||||
final override string toString() {
|
||||
result = call.toString() + " at " + call.getLocation() // This isn't performant, but it's only used in test/dump code right now.
|
||||
// This isn't performant, but it's only used in test/dump code right now.
|
||||
// Dynamic allocations within a function are numbered in the order by start
|
||||
// line number. This keeps them stable when the function moves within the
|
||||
// file, or when non-allocating lines are added and removed within the
|
||||
// function.
|
||||
exists(int i |
|
||||
result = "dynamic{" + i.toString() + "}" and
|
||||
call =
|
||||
rank[i](CallInstruction rangeCall |
|
||||
exists(TDynamicAllocation(rangeCall)) and
|
||||
rangeCall.getEnclosingIRFunction() = call.getEnclosingIRFunction()
|
||||
|
|
||||
rangeCall order by rangeCall.getLocation().getStartLine()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
final override CallInstruction getABaseInstruction() { result = call }
|
||||
|
||||
@@ -1645,6 +1645,19 @@ class CallInstruction extends Instruction {
|
||||
* Gets the number of arguments of the call, including the `this` pointer, if any.
|
||||
*/
|
||||
final int getNumberOfArguments() { result = count(this.getAnArgumentOperand()) }
|
||||
|
||||
/**
|
||||
* Holds if the result is a side effect for the argument at the specified index, or `this` if
|
||||
* `index` is `-1`.
|
||||
*
|
||||
* This helper predicate makes it easy to join on both of these columns at once, avoiding
|
||||
* pathological join orders in case the argument index should get joined first.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final SideEffectInstruction getAParameterSideEffect(int index) {
|
||||
this = result.getPrimaryInstruction() and
|
||||
index = result.(IndexedInstruction).getIndex()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1645,6 +1645,19 @@ class CallInstruction extends Instruction {
|
||||
* Gets the number of arguments of the call, including the `this` pointer, if any.
|
||||
*/
|
||||
final int getNumberOfArguments() { result = count(this.getAnArgumentOperand()) }
|
||||
|
||||
/**
|
||||
* Holds if the result is a side effect for the argument at the specified index, or `this` if
|
||||
* `index` is `-1`.
|
||||
*
|
||||
* This helper predicate makes it easy to join on both of these columns at once, avoiding
|
||||
* pathological join orders in case the argument index should get joined first.
|
||||
*/
|
||||
pragma[noinline]
|
||||
final SideEffectInstruction getAParameterSideEffect(int index) {
|
||||
this = result.getPrimaryInstruction() and
|
||||
index = result.(IndexedInstruction).getIndex()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,71 @@ private import AliasAnalysisImports
|
||||
|
||||
private class IntValue = Ints::IntValue;
|
||||
|
||||
/**
|
||||
* If `instr` is a `SideEffectInstruction`, gets the primary `CallInstruction` that caused the side
|
||||
* effect. If `instr` is a `CallInstruction`, gets that same `CallInstruction`.
|
||||
*/
|
||||
private CallInstruction getPrimaryCall(Instruction instr) {
|
||||
result = instr
|
||||
or
|
||||
result = instr.(SideEffectInstruction).getPrimaryInstruction()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operand` serves as an input argument (or indirection) to `call`, in the position
|
||||
* specified by `input`.
|
||||
*/
|
||||
private predicate isCallInput(
|
||||
CallInstruction call, Operand operand, AliasModels::FunctionInput input
|
||||
) {
|
||||
call = getPrimaryCall(operand.getUse()) and
|
||||
(
|
||||
exists(int index |
|
||||
input.isParameterOrQualifierAddress(index) and
|
||||
operand = call.getArgumentOperand(index)
|
||||
)
|
||||
or
|
||||
exists(int index, ReadSideEffectInstruction read |
|
||||
input.isParameterDerefOrQualifierObject(index) and
|
||||
read = call.getAParameterSideEffect(index) and
|
||||
operand = read.getSideEffectOperand()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `instr` serves as a return value or output argument indirection for `call`, in the
|
||||
* position specified by `output`.
|
||||
*/
|
||||
private predicate isCallOutput(
|
||||
CallInstruction call, Instruction instr, AliasModels::FunctionOutput output
|
||||
) {
|
||||
call = getPrimaryCall(instr) and
|
||||
(
|
||||
output.isReturnValue() and instr = call
|
||||
or
|
||||
exists(int index, WriteSideEffectInstruction write |
|
||||
output.isParameterDerefOrQualifierObject(index) and
|
||||
write = call.getAParameterSideEffect(index) and
|
||||
instr = write
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the address in `operand` flows directly to the result of `resultInstr` due to modeled
|
||||
* address flow through a function call.
|
||||
*/
|
||||
private predicate hasAddressFlowThroughCall(Operand operand, Instruction resultInstr) {
|
||||
exists(
|
||||
CallInstruction call, AliasModels::FunctionInput input, AliasModels::FunctionOutput output
|
||||
|
|
||||
call.getStaticCallTarget().(AliasModels::AliasFunction).hasAddressFlow(input, output) and
|
||||
isCallInput(call, operand, input) and
|
||||
isCallOutput(call, resultInstr, output)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the operand `tag` of instruction `instr` is used in a way that does
|
||||
* not result in any address held in that operand from escaping beyond the
|
||||
@@ -34,7 +99,7 @@ private predicate operandIsConsumedWithoutEscaping(Operand operand) {
|
||||
|
||||
private predicate operandEscapesDomain(Operand operand) {
|
||||
not operandIsConsumedWithoutEscaping(operand) and
|
||||
not operandIsPropagated(operand, _) and
|
||||
not operandIsPropagated(operand, _, _) and
|
||||
not isArgumentForParameter(_, operand, _) and
|
||||
not isOnlyEscapesViaReturnArgument(operand) and
|
||||
not operand.getUse() instanceof ReturnValueInstruction and
|
||||
@@ -69,67 +134,67 @@ IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if any address held in operand `tag` of instruction `instr` is
|
||||
* propagated to the result of `instr`, offset by the number of bits in
|
||||
* `bitOffset`. If the address is propagated, but the offset is not known to be
|
||||
* a constant, then `bitOffset` is unknown.
|
||||
* Holds if any address held in operand `operand` is propagated to the result of `instr`, offset by
|
||||
* the number of bits in `bitOffset`. If the address is propagated, but the offset is not known to
|
||||
* be a constant, then `bitOffset` is `unknown()`.
|
||||
*/
|
||||
private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
|
||||
exists(Instruction instr |
|
||||
instr = operand.getUse() and
|
||||
(
|
||||
// Converting to a non-virtual base class adds the offset of the base class.
|
||||
exists(ConvertToNonVirtualBaseInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
)
|
||||
or
|
||||
// Conversion using dynamic_cast results in an unknown offset
|
||||
instr instanceof CheckedConvertOrNullInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
|
||||
)
|
||||
or
|
||||
// Converting to a virtual base class adds an unknown offset.
|
||||
instr instanceof ConvertToVirtualBaseInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
or
|
||||
// Conversion to another pointer type propagates the source address.
|
||||
exists(ConvertInstruction convert, IRType resultType |
|
||||
convert = instr and
|
||||
resultType = convert.getResultIRType() and
|
||||
resultType instanceof IRAddressType and
|
||||
bitOffset = 0
|
||||
)
|
||||
or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
exists(PointerOffsetInstruction ptrOffset |
|
||||
ptrOffset = instr and
|
||||
operand = ptrOffset.getLeftOperand() and
|
||||
bitOffset = getPointerBitOffset(ptrOffset)
|
||||
)
|
||||
or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
bitOffset = Language::getFieldBitOffset(instr.(FieldAddressInstruction).getField())
|
||||
or
|
||||
// A copy propagates the source value.
|
||||
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
|
||||
or
|
||||
// Some functions are known to propagate an argument
|
||||
isAlwaysReturnedArgument(operand) and bitOffset = 0
|
||||
private predicate operandIsPropagated(Operand operand, IntValue bitOffset, Instruction instr) {
|
||||
// Some functions are known to propagate an argument
|
||||
hasAddressFlowThroughCall(operand, instr) and
|
||||
bitOffset = 0
|
||||
or
|
||||
instr = operand.getUse() and
|
||||
(
|
||||
// Converting to a non-virtual base class adds the offset of the base class.
|
||||
exists(ConvertToNonVirtualBaseInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
|
||||
)
|
||||
or
|
||||
// Conversion using dynamic_cast results in an unknown offset
|
||||
instr instanceof CheckedConvertOrNullInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
or
|
||||
// Converting to a derived class subtracts the offset of the base class.
|
||||
exists(ConvertToDerivedInstruction convert |
|
||||
convert = instr and
|
||||
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
|
||||
)
|
||||
or
|
||||
// Converting to a virtual base class adds an unknown offset.
|
||||
instr instanceof ConvertToVirtualBaseInstruction and
|
||||
bitOffset = Ints::unknown()
|
||||
or
|
||||
// Conversion to another pointer type propagates the source address.
|
||||
exists(ConvertInstruction convert, IRType resultType |
|
||||
convert = instr and
|
||||
resultType = convert.getResultIRType() and
|
||||
resultType instanceof IRAddressType and
|
||||
bitOffset = 0
|
||||
)
|
||||
or
|
||||
// Adding an integer to or subtracting an integer from a pointer propagates
|
||||
// the address with an offset.
|
||||
exists(PointerOffsetInstruction ptrOffset |
|
||||
ptrOffset = instr and
|
||||
operand = ptrOffset.getLeftOperand() and
|
||||
bitOffset = getPointerBitOffset(ptrOffset)
|
||||
)
|
||||
or
|
||||
// Computing a field address from a pointer propagates the address plus the
|
||||
// offset of the field.
|
||||
bitOffset = Language::getFieldBitOffset(instr.(FieldAddressInstruction).getField())
|
||||
or
|
||||
// A copy propagates the source value.
|
||||
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
|
||||
)
|
||||
}
|
||||
|
||||
private predicate operandEscapesNonReturn(Operand operand) {
|
||||
// The address is propagated to the result of the instruction, and that result itself is returned
|
||||
operandIsPropagated(operand, _) and resultEscapesNonReturn(operand.getUse())
|
||||
exists(Instruction instr |
|
||||
// The address is propagated to the result of the instruction, and that result itself is returned
|
||||
operandIsPropagated(operand, _, instr) and resultEscapesNonReturn(instr)
|
||||
)
|
||||
or
|
||||
// The operand is used in a function call which returns it, and the return value is then returned
|
||||
exists(CallInstruction ci, Instruction init |
|
||||
@@ -151,9 +216,11 @@ private predicate operandEscapesNonReturn(Operand 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.getUse())
|
||||
exists(Instruction instr |
|
||||
// The address is propagated to the result of the instruction, and that result itself is returned
|
||||
operandIsPropagated(operand, _, instr) and
|
||||
resultMayReachReturn(instr)
|
||||
)
|
||||
or
|
||||
// The operand is used in a function call which returns it, and the return value is then returned
|
||||
exists(CallInstruction ci, Instruction init |
|
||||
@@ -173,9 +240,9 @@ private predicate operandMayReachReturn(Operand operand) {
|
||||
|
||||
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.getUse(), bitOffset2) and
|
||||
exists(Instruction instr, IntValue bitOffset1, IntValue bitOffset2 |
|
||||
operandIsPropagated(operand, bitOffset1, instr) and
|
||||
resultReturned(instr, bitOffset2) and
|
||||
bitOffset = Ints::add(bitOffset1, bitOffset2)
|
||||
)
|
||||
or
|
||||
@@ -214,13 +281,6 @@ private predicate isArgumentForParameter(
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isAlwaysReturnedArgument(Operand operand) {
|
||||
exists(AliasModels::AliasFunction f |
|
||||
f = operand.getUse().(CallInstruction).getStaticCallTarget() and
|
||||
f.parameterIsAlwaysReturned(operand.(PositionalArgumentOperand).getIndex())
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isOnlyEscapesViaReturnArgument(Operand operand) {
|
||||
exists(AliasModels::AliasFunction f |
|
||||
f = operand.getUse().(CallInstruction).getStaticCallTarget() and
|
||||
@@ -270,12 +330,15 @@ predicate allocationEscapes(Configuration::Allocation allocation) {
|
||||
/**
|
||||
* Equivalent to `operandIsPropagated()`, but includes interprocedural propagation.
|
||||
*/
|
||||
private predicate operandIsPropagatedIncludingByCall(Operand operand, IntValue bitOffset) {
|
||||
operandIsPropagated(operand, bitOffset)
|
||||
private predicate operandIsPropagatedIncludingByCall(
|
||||
Operand operand, IntValue bitOffset, Instruction instr
|
||||
) {
|
||||
operandIsPropagated(operand, bitOffset, instr)
|
||||
or
|
||||
exists(CallInstruction call, Instruction init |
|
||||
isArgumentForParameter(call, operand, init) and
|
||||
resultReturned(init, bitOffset)
|
||||
resultReturned(init, bitOffset) and
|
||||
instr = call
|
||||
)
|
||||
}
|
||||
|
||||
@@ -292,8 +355,7 @@ private predicate hasBaseAndOffset(AddressOperand addrOperand, Instruction base,
|
||||
// We already have an offset from `middle`.
|
||||
hasBaseAndOffset(addrOperand, middle, previousBitOffset) and
|
||||
// `middle` is propagated from `base`.
|
||||
middleOperand = middle.getAnOperand() and
|
||||
operandIsPropagatedIncludingByCall(middleOperand, additionalBitOffset) and
|
||||
operandIsPropagatedIncludingByCall(middleOperand, additionalBitOffset, middle) and
|
||||
base = middleOperand.getDef() and
|
||||
bitOffset = Ints::add(previousBitOffset, additionalBitOffset)
|
||||
)
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.SideEffect
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.DataFlow
|
||||
import semmle.code.cpp.models.interfaces.PointerWrapper
|
||||
|
||||
/**
|
||||
* The `std::shared_ptr` and `std::unique_ptr` template classes.
|
||||
* The `std::shared_ptr`, `std::weak_ptr`, and `std::unique_ptr` template classes.
|
||||
*/
|
||||
private class UniqueOrSharedPtr extends Class, PointerWrapper {
|
||||
UniqueOrSharedPtr() { this.hasQualifiedName(["std", "bsl"], ["shared_ptr", "unique_ptr"]) }
|
||||
private class SmartPtr extends Class, PointerWrapper {
|
||||
SmartPtr() { this.hasQualifiedName(["std", "bsl"], ["shared_ptr", "weak_ptr", "unique_ptr"]) }
|
||||
|
||||
override MemberFunction getAnUnwrapperFunction() {
|
||||
result.(OverloadedPointerDereferenceFunction).getDeclaringType() = this
|
||||
@@ -17,11 +19,19 @@ private class UniqueOrSharedPtr extends Class, PointerWrapper {
|
||||
override predicate pointsToConst() { this.getTemplateArgument(0).(Type).isConst() }
|
||||
}
|
||||
|
||||
/** Any function that unwraps a pointer wrapper class to reveal the underlying pointer. */
|
||||
private class PointerWrapperFlow extends TaintFunction, DataFlowFunction {
|
||||
PointerWrapperFlow() {
|
||||
this = any(PointerWrapper wrapper).getAnUnwrapperFunction() and
|
||||
not this.getUnspecifiedType() instanceof ReferenceType
|
||||
/**
|
||||
* Any function that returns the address wrapped by a `PointerWrapper`, whether as a pointer or a
|
||||
* reference.
|
||||
*
|
||||
* Examples:
|
||||
* - `std::unique_ptr<T>::get()`
|
||||
* - `std::shared_ptr<T>::operator->()`
|
||||
* - `std::weak_ptr<T>::operator*()`
|
||||
*/
|
||||
private class PointerUnwrapperFunction extends MemberFunction, TaintFunction, DataFlowFunction,
|
||||
SideEffectFunction, AliasFunction {
|
||||
PointerUnwrapperFunction() {
|
||||
exists(PointerWrapper wrapper | wrapper.getAnUnwrapperFunction() = this)
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
@@ -32,6 +42,23 @@ private class PointerWrapperFlow extends TaintFunction, DataFlowFunction {
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and output.isReturnValue()
|
||||
}
|
||||
|
||||
override predicate hasOnlySpecificReadSideEffects() { any() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
// Only reads from `*this`.
|
||||
i = -1 and buffer = false
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasAddressFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,31 +89,80 @@ private class MakeUniqueOrShared extends TaintFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* A prefix `operator*` member function for a `shared_ptr` or `unique_ptr` type.
|
||||
* A function that sets the value of a smart pointer.
|
||||
*
|
||||
* This could be a constructor, an assignment operator, or a named member function like `reset()`.
|
||||
*/
|
||||
private class UniqueOrSharedDereferenceMemberOperator extends MemberFunction, TaintFunction {
|
||||
UniqueOrSharedDereferenceMemberOperator() {
|
||||
this.hasName("operator*") and
|
||||
this.getDeclaringType() instanceof UniqueOrSharedPtr
|
||||
private class SmartPtrSetterFunction extends MemberFunction, AliasFunction, SideEffectFunction {
|
||||
SmartPtrSetterFunction() {
|
||||
this.getDeclaringType() instanceof SmartPtr and
|
||||
not this.isStatic() and
|
||||
(
|
||||
this instanceof Constructor
|
||||
or
|
||||
this.hasName("operator=")
|
||||
or
|
||||
this.hasName("reset")
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
override predicate hasOnlySpecificReadSideEffects() { none() }
|
||||
|
||||
/**
|
||||
* The `std::shared_ptr` or `std::unique_ptr` function `get`.
|
||||
*/
|
||||
private class UniqueOrSharedGet extends TaintFunction {
|
||||
UniqueOrSharedGet() {
|
||||
this.hasName("get") and
|
||||
this.getDeclaringType() instanceof UniqueOrSharedPtr
|
||||
override predicate hasOnlySpecificWriteSideEffects() { none() }
|
||||
|
||||
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
|
||||
// Always write to the destination smart pointer itself.
|
||||
i = -1 and buffer = false and mustWrite = true
|
||||
or
|
||||
// When taking ownership of a smart pointer via an rvalue reference, always overwrite the input
|
||||
// smart pointer.
|
||||
getPointerInput().isParameterDeref(i) and
|
||||
this.getParameter(i).getUnspecifiedType() instanceof RValueReferenceType and
|
||||
buffer = false and
|
||||
mustWrite = true
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
getPointerInput().isParameterDeref(i) and
|
||||
buffer = false
|
||||
or
|
||||
not this instanceof Constructor and
|
||||
i = -1 and
|
||||
buffer = false
|
||||
}
|
||||
|
||||
override predicate parameterNeverEscapes(int index) { index = -1 }
|
||||
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
|
||||
|
||||
override predicate hasAddressFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = getPointerInput() and
|
||||
output.isQualifierObject()
|
||||
or
|
||||
// Assignment operator always returns a reference to `*this`.
|
||||
this.hasName("operator=") and
|
||||
input.isQualifierAddress() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
|
||||
private FunctionInput getPointerInput() {
|
||||
exists(Parameter param0 |
|
||||
param0 = this.getParameter(0) and
|
||||
(
|
||||
param0.getUnspecifiedType().(ReferenceType).getBaseType() instanceof SmartPtr and
|
||||
if this.getParameter(1).getUnspecifiedType() instanceof PointerType
|
||||
then
|
||||
// This is one of the constructors of `std::shared_ptr<T>` that creates a smart pointer that
|
||||
// wraps a raw pointer with ownership controlled by an unrelated smart pointer. We propagate
|
||||
// the raw pointer in the second parameter, rather than the smart pointer in the first
|
||||
// parameter.
|
||||
result.isParameter(1)
|
||||
else result.isParameterDeref(0)
|
||||
)
|
||||
or
|
||||
// One of the functions that takes ownership of a raw pointer.
|
||||
param0.getUnspecifiedType() instanceof PointerType and
|
||||
result.isParameter(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,5 +50,16 @@ abstract class AliasFunction extends Function {
|
||||
/**
|
||||
* Holds if the function always returns the value of the parameter at the specified index.
|
||||
*/
|
||||
abstract predicate parameterIsAlwaysReturned(int index);
|
||||
predicate parameterIsAlwaysReturned(int index) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the address passed in via `input` is always propagated to `output`.
|
||||
*/
|
||||
predicate hasAddressFlow(FunctionInput input, FunctionOutput output) {
|
||||
exists(int index |
|
||||
// By default, just use the old `parameterIsAlwaysReturned` predicate to detect flow from the
|
||||
// parameter to the return value.
|
||||
input.isParameter(index) and output.isReturnValue() and this.parameterIsAlwaysReturned(index)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
139
cpp/ql/test/include/memory.h
Normal file
139
cpp/ql/test/include/memory.h
Normal file
@@ -0,0 +1,139 @@
|
||||
#if !defined(CODEQL_MEMORY_H)
|
||||
#define CODEQL_MEMORY_H
|
||||
|
||||
namespace std {
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
class compressed_pair_element {
|
||||
T element;
|
||||
|
||||
public:
|
||||
compressed_pair_element() = default;
|
||||
compressed_pair_element(const T& t) : element(t) {}
|
||||
|
||||
T& get() { return element; }
|
||||
|
||||
const T& get() const { return element; }
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
struct compressed_pair : private compressed_pair_element<T>, private compressed_pair_element<U> {
|
||||
compressed_pair() = default;
|
||||
compressed_pair(T& t) : compressed_pair_element<T>(t), compressed_pair_element<U>() {}
|
||||
compressed_pair(const compressed_pair&) = delete;
|
||||
compressed_pair(compressed_pair<T, U>&&) noexcept = default;
|
||||
|
||||
T& first() { return static_cast<compressed_pair_element<T>&>(*this).get(); }
|
||||
U& second() { return static_cast<compressed_pair_element<U>&>(*this).get(); }
|
||||
|
||||
const T& first() const { return static_cast<const compressed_pair_element<T>&>(*this).get(); }
|
||||
const U& second() const { return static_cast<const compressed_pair_element<U>&>(*this).get(); }
|
||||
};
|
||||
}
|
||||
|
||||
template<class T>
|
||||
struct default_delete {
|
||||
void operator()(T* ptr) const { delete ptr; }
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct default_delete<T[]> {
|
||||
template<class U>
|
||||
void operator()(U* ptr) const { delete[] ptr; }
|
||||
};
|
||||
|
||||
template<class T, class Deleter = default_delete<T> >
|
||||
class unique_ptr {
|
||||
private:
|
||||
detail::compressed_pair<T*, Deleter> data;
|
||||
public:
|
||||
constexpr unique_ptr() noexcept {}
|
||||
explicit unique_ptr(T* ptr) noexcept : data(ptr) {}
|
||||
unique_ptr(const unique_ptr& ptr) = delete;
|
||||
unique_ptr(unique_ptr&& ptr) noexcept = default;
|
||||
|
||||
unique_ptr& operator=(unique_ptr&& ptr) noexcept = default;
|
||||
|
||||
T& operator*() const { return *get(); }
|
||||
T* operator->() const noexcept { return get(); }
|
||||
|
||||
T* get() const noexcept { return data.first(); }
|
||||
T* release() noexcept {
|
||||
Deleter& d = data.second();
|
||||
d(data.first());
|
||||
data.first() = nullptr;
|
||||
}
|
||||
|
||||
~unique_ptr() {
|
||||
Deleter& d = data.second();
|
||||
d(data.first());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, class... Args> unique_ptr<T> make_unique(Args&&... args) {
|
||||
return unique_ptr<T>(new T(args...)); // std::forward calls elided for simplicity.
|
||||
}
|
||||
|
||||
class ctrl_block {
|
||||
unsigned uses;
|
||||
|
||||
public:
|
||||
ctrl_block() : uses(1) {}
|
||||
|
||||
void inc() { ++uses; }
|
||||
bool dec() { return --uses == 0; }
|
||||
|
||||
virtual void destroy() = 0;
|
||||
virtual ~ctrl_block() {}
|
||||
};
|
||||
|
||||
template<typename T, class Deleter = default_delete<T> >
|
||||
struct ctrl_block_impl: public ctrl_block {
|
||||
T* ptr;
|
||||
Deleter d;
|
||||
|
||||
ctrl_block_impl(T* ptr, Deleter d) : ptr(ptr), d(d) {}
|
||||
virtual void destroy() override { d(ptr); }
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class shared_ptr {
|
||||
private:
|
||||
ctrl_block* ctrl;
|
||||
T* ptr;
|
||||
|
||||
void dec() {
|
||||
if(ctrl->dec()) {
|
||||
ctrl->destroy();
|
||||
delete ctrl;
|
||||
}
|
||||
}
|
||||
|
||||
void inc() {
|
||||
ctrl->inc();
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr shared_ptr() noexcept = default;
|
||||
shared_ptr(T* ptr) : ctrl(new ctrl_block_impl<T>(ptr, default_delete<T>())) {}
|
||||
shared_ptr(const shared_ptr& s) noexcept : ptr(s.ptr), ctrl(s.ctrl) {
|
||||
inc();
|
||||
}
|
||||
shared_ptr(shared_ptr&& s) noexcept = default;
|
||||
shared_ptr(unique_ptr<T>&& s) : shared_ptr(s.release()) {
|
||||
}
|
||||
T* operator->() const { return ptr; }
|
||||
|
||||
T& operator*() const { return *ptr; }
|
||||
|
||||
T* get() const noexcept { return ptr; }
|
||||
|
||||
~shared_ptr() { dec(); }
|
||||
};
|
||||
|
||||
template<typename T, class... Args> shared_ptr<T> make_shared(Args&&... args) {
|
||||
return shared_ptr<T>(new T(args...)); // std::forward calls elided for simplicity.
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
21
cpp/ql/test/include/type_traits.h
Normal file
21
cpp/ql/test/include/type_traits.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#if !defined(CODEQL_TYPE_TRAITS_H)
|
||||
#define CODEQL_TYPE_TRAITS_H
|
||||
|
||||
namespace std {
|
||||
template<typename T>
|
||||
struct remove_reference {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct remove_reference<T&> {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct remove_reference<T&&> {
|
||||
typedef T type;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
13
cpp/ql/test/include/utility.h
Normal file
13
cpp/ql/test/include/utility.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#if !defined(CODEQL_UTILITY_H)
|
||||
#define CODEQL_UTILITY_H
|
||||
|
||||
#include "type_traits.h"
|
||||
|
||||
namespace std {
|
||||
template<typename T>
|
||||
typename remove_reference<T>::type&& move(T&& src) {
|
||||
return static_cast<typename remove_reference<T>::type&&>(src);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -7,7 +7,7 @@ void test_unique_ptr_int() {
|
||||
std::unique_ptr<int> p1(new int(source()));
|
||||
std::unique_ptr<int> p2 = std::make_unique<int>(source());
|
||||
|
||||
sink(*p1); // $ MISSING: ast,ir
|
||||
sink(*p1); // $ ir MISSING: ast
|
||||
sink(*p2); // $ ast ir=8:50
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ void test_unique_ptr_struct() {
|
||||
std::unique_ptr<A> p1(new A{source(), 0});
|
||||
std::unique_ptr<A> p2 = std::make_unique<A>(source(), 0);
|
||||
|
||||
sink(p1->x); // $ MISSING: ast,ir
|
||||
sink(p1->x); // $ ir MISSING: ast
|
||||
sink(p1->y);
|
||||
sink(p2->x); // $ MISSING: ast,ir
|
||||
sink(p2->y);
|
||||
@@ -31,7 +31,7 @@ void test_shared_ptr_int() {
|
||||
std::shared_ptr<int> p1(new int(source()));
|
||||
std::shared_ptr<int> p2 = std::make_shared<int>(source());
|
||||
|
||||
sink(*p1); // $ ast
|
||||
sink(*p1); // $ ast ir
|
||||
sink(*p2); // $ ast ir=32:50
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ void test_shared_ptr_struct() {
|
||||
std::shared_ptr<A> p1(new A{source(), 0});
|
||||
std::shared_ptr<A> p2 = std::make_shared<A>(source(), 0);
|
||||
|
||||
sink(p1->x); // $ MISSING: ast,ir
|
||||
sink(p1->x); // $ ir MISSING: ast
|
||||
sink(p1->y);
|
||||
sink(p2->x); // $ MISSING: ast,ir
|
||||
sink(p2->y);
|
||||
|
||||
@@ -3228,6 +3228,7 @@
|
||||
| smart_pointer.cpp:17:32:17:54 | call to make_shared | smart_pointer.cpp:18:11:18:11 | p | |
|
||||
| smart_pointer.cpp:17:32:17:54 | call to make_shared | smart_pointer.cpp:19:10:19:10 | p | |
|
||||
| smart_pointer.cpp:18:10:18:10 | ref arg call to operator* | smart_pointer.cpp:18:11:18:11 | p [inner post update] | |
|
||||
| smart_pointer.cpp:18:10:18:10 | ref arg call to operator* | smart_pointer.cpp:18:11:18:11 | ref arg p | TAINT |
|
||||
| smart_pointer.cpp:18:10:18:10 | ref arg call to operator* | smart_pointer.cpp:19:10:19:10 | p | |
|
||||
| smart_pointer.cpp:18:11:18:11 | p | smart_pointer.cpp:18:10:18:10 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:18:11:18:11 | ref arg p | smart_pointer.cpp:18:11:18:11 | p [inner post update] | |
|
||||
@@ -3240,6 +3241,7 @@
|
||||
| smart_pointer.cpp:29:32:29:54 | call to make_unique | smart_pointer.cpp:30:11:30:11 | p | |
|
||||
| smart_pointer.cpp:29:32:29:54 | call to make_unique | smart_pointer.cpp:31:10:31:10 | p | |
|
||||
| smart_pointer.cpp:30:10:30:10 | ref arg call to operator* | smart_pointer.cpp:30:11:30:11 | p [inner post update] | |
|
||||
| smart_pointer.cpp:30:10:30:10 | ref arg call to operator* | smart_pointer.cpp:30:11:30:11 | ref arg p | TAINT |
|
||||
| smart_pointer.cpp:30:10:30:10 | ref arg call to operator* | smart_pointer.cpp:31:10:31:10 | p | |
|
||||
| smart_pointer.cpp:30:11:30:11 | p | smart_pointer.cpp:30:10:30:10 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:30:11:30:11 | ref arg p | smart_pointer.cpp:30:11:30:11 | p [inner post update] | |
|
||||
@@ -3248,6 +3250,7 @@
|
||||
| smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:38:10:38:10 | p | |
|
||||
| smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:39:11:39:11 | p | |
|
||||
| smart_pointer.cpp:37:5:37:5 | call to operator* [post update] | smart_pointer.cpp:37:6:37:6 | p [inner post update] | |
|
||||
| smart_pointer.cpp:37:5:37:5 | call to operator* [post update] | smart_pointer.cpp:37:6:37:6 | ref arg p | TAINT |
|
||||
| smart_pointer.cpp:37:5:37:5 | call to operator* [post update] | smart_pointer.cpp:38:10:38:10 | p | |
|
||||
| smart_pointer.cpp:37:5:37:5 | call to operator* [post update] | smart_pointer.cpp:39:11:39:11 | p | |
|
||||
| smart_pointer.cpp:37:5:37:17 | ... = ... | smart_pointer.cpp:37:5:37:5 | call to operator* [post update] | |
|
||||
@@ -3262,6 +3265,7 @@
|
||||
| smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:46:10:46:10 | p | |
|
||||
| smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:47:11:47:11 | p | |
|
||||
| smart_pointer.cpp:45:5:45:5 | call to operator* [post update] | smart_pointer.cpp:45:6:45:6 | p [inner post update] | |
|
||||
| smart_pointer.cpp:45:5:45:5 | call to operator* [post update] | smart_pointer.cpp:45:6:45:6 | ref arg p | TAINT |
|
||||
| smart_pointer.cpp:45:5:45:5 | call to operator* [post update] | smart_pointer.cpp:46:10:46:10 | p | |
|
||||
| smart_pointer.cpp:45:5:45:5 | call to operator* [post update] | smart_pointer.cpp:47:11:47:11 | p | |
|
||||
| smart_pointer.cpp:45:5:45:17 | ... = ... | smart_pointer.cpp:45:5:45:5 | call to operator* [post update] | |
|
||||
@@ -3291,6 +3295,7 @@
|
||||
| smart_pointer.cpp:70:37:70:39 | ptr | smart_pointer.cpp:71:4:71:6 | ptr | |
|
||||
| smart_pointer.cpp:71:3:71:3 | call to operator* [post update] | smart_pointer.cpp:70:37:70:39 | ptr | |
|
||||
| smart_pointer.cpp:71:3:71:3 | call to operator* [post update] | smart_pointer.cpp:71:4:71:6 | ptr [inner post update] | |
|
||||
| smart_pointer.cpp:71:3:71:3 | call to operator* [post update] | smart_pointer.cpp:71:4:71:6 | ref arg ptr | TAINT |
|
||||
| smart_pointer.cpp:71:3:71:17 | ... = ... | smart_pointer.cpp:71:3:71:3 | call to operator* [post update] | |
|
||||
| smart_pointer.cpp:71:4:71:6 | ptr | smart_pointer.cpp:71:3:71:3 | call to operator* | |
|
||||
| smart_pointer.cpp:71:4:71:6 | ref arg ptr | smart_pointer.cpp:70:37:70:39 | ptr | |
|
||||
@@ -3371,6 +3376,7 @@
|
||||
| smart_pointer.cpp:120:48:120:50 | ptr | smart_pointer.cpp:121:4:121:6 | ptr | |
|
||||
| smart_pointer.cpp:121:3:121:3 | call to operator* [post update] | smart_pointer.cpp:120:48:120:50 | ptr | |
|
||||
| smart_pointer.cpp:121:3:121:3 | call to operator* [post update] | smart_pointer.cpp:121:4:121:6 | ptr [inner post update] | |
|
||||
| smart_pointer.cpp:121:3:121:3 | call to operator* [post update] | smart_pointer.cpp:121:4:121:6 | ref arg ptr | TAINT |
|
||||
| smart_pointer.cpp:121:3:121:17 | ... = ... | smart_pointer.cpp:121:3:121:3 | call to operator* [post update] | |
|
||||
| smart_pointer.cpp:121:4:121:6 | ptr | smart_pointer.cpp:121:3:121:3 | call to operator* | |
|
||||
| smart_pointer.cpp:121:4:121:6 | ref arg ptr | smart_pointer.cpp:120:48:120:50 | ptr | |
|
||||
@@ -3394,9 +3400,11 @@
|
||||
| smart_pointer.cpp:126:10:126:10 | call to operator-> [post update] | smart_pointer.cpp:126:8:126:9 | ref arg p1 | TAINT |
|
||||
| smart_pointer.cpp:126:12:126:12 | q | smart_pointer.cpp:126:13:126:13 | call to operator-> | |
|
||||
| smart_pointer.cpp:128:13:128:13 | call to operator* | smart_pointer.cpp:128:13:128:15 | call to shared_ptr | TAINT |
|
||||
| smart_pointer.cpp:128:13:128:13 | call to operator* [inner post update] | smart_pointer.cpp:128:14:128:15 | ref arg p2 | TAINT |
|
||||
| smart_pointer.cpp:128:13:128:13 | ref arg call to operator* | smart_pointer.cpp:124:90:124:91 | p2 | |
|
||||
| smart_pointer.cpp:128:13:128:13 | ref arg call to operator* | smart_pointer.cpp:128:13:128:13 | call to operator* [inner post update] | |
|
||||
| smart_pointer.cpp:128:13:128:13 | ref arg call to operator* | smart_pointer.cpp:128:14:128:15 | p2 [inner post update] | |
|
||||
| smart_pointer.cpp:128:13:128:13 | ref arg call to operator* | smart_pointer.cpp:128:14:128:15 | ref arg p2 | TAINT |
|
||||
| smart_pointer.cpp:128:13:128:13 | ref arg call to operator* | smart_pointer.cpp:129:10:129:11 | p2 | |
|
||||
| smart_pointer.cpp:128:13:128:15 | ref arg call to shared_ptr | smart_pointer.cpp:124:90:124:91 | p2 | |
|
||||
| smart_pointer.cpp:128:13:128:15 | ref arg call to shared_ptr | smart_pointer.cpp:128:13:128:13 | call to operator* [inner post update] | |
|
||||
@@ -3409,6 +3417,7 @@
|
||||
| smart_pointer.cpp:129:9:129:9 | call to operator* | smart_pointer.cpp:129:8:129:8 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:129:9:129:9 | ref arg call to operator* | smart_pointer.cpp:124:90:124:91 | p2 | |
|
||||
| smart_pointer.cpp:129:9:129:9 | ref arg call to operator* | smart_pointer.cpp:129:10:129:11 | p2 [inner post update] | |
|
||||
| smart_pointer.cpp:129:9:129:9 | ref arg call to operator* | smart_pointer.cpp:129:10:129:11 | ref arg p2 | TAINT |
|
||||
| smart_pointer.cpp:129:10:129:11 | p2 | smart_pointer.cpp:129:8:129:8 | call to operator* | |
|
||||
| smart_pointer.cpp:129:10:129:11 | p2 | smart_pointer.cpp:129:9:129:9 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:129:10:129:11 | ref arg p2 | smart_pointer.cpp:124:90:124:91 | p2 | |
|
||||
@@ -3429,6 +3438,7 @@
|
||||
| smart_pointer.cpp:134:12:134:12 | q | smart_pointer.cpp:134:13:134:13 | call to operator-> | |
|
||||
| smart_pointer.cpp:136:17:136:17 | ref arg call to operator* | smart_pointer.cpp:132:95:132:96 | p2 | |
|
||||
| smart_pointer.cpp:136:17:136:17 | ref arg call to operator* | smart_pointer.cpp:136:18:136:19 | p2 [inner post update] | |
|
||||
| smart_pointer.cpp:136:17:136:17 | ref arg call to operator* | smart_pointer.cpp:136:18:136:19 | ref arg p2 | TAINT |
|
||||
| smart_pointer.cpp:136:17:136:17 | ref arg call to operator* | smart_pointer.cpp:137:10:137:11 | p2 | |
|
||||
| smart_pointer.cpp:136:18:136:19 | p2 | smart_pointer.cpp:136:17:136:17 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:136:18:136:19 | ref arg p2 | smart_pointer.cpp:132:95:132:96 | p2 | |
|
||||
@@ -3437,6 +3447,7 @@
|
||||
| smart_pointer.cpp:137:9:137:9 | call to operator* | smart_pointer.cpp:137:8:137:8 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:137:9:137:9 | ref arg call to operator* | smart_pointer.cpp:132:95:132:96 | p2 | |
|
||||
| smart_pointer.cpp:137:9:137:9 | ref arg call to operator* | smart_pointer.cpp:137:10:137:11 | p2 [inner post update] | |
|
||||
| smart_pointer.cpp:137:9:137:9 | ref arg call to operator* | smart_pointer.cpp:137:10:137:11 | ref arg p2 | TAINT |
|
||||
| smart_pointer.cpp:137:10:137:11 | p2 | smart_pointer.cpp:137:8:137:8 | call to operator* | |
|
||||
| smart_pointer.cpp:137:10:137:11 | p2 | smart_pointer.cpp:137:9:137:9 | call to operator* | TAINT |
|
||||
| smart_pointer.cpp:137:10:137:11 | ref arg p2 | smart_pointer.cpp:132:95:132:96 | p2 | |
|
||||
@@ -3532,13 +3543,13 @@
|
||||
| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:120:2:120:3 | it | |
|
||||
| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:121:7:121:8 | it | |
|
||||
| standalone_iterators.cpp:117:7:117:8 | it [post update] | standalone_iterators.cpp:122:7:122:8 | c1 | |
|
||||
| standalone_iterators.cpp:118:2:118:3 | it | standalone_iterators.cpp:118:5:118:5 | call to operator+= | |
|
||||
| standalone_iterators.cpp:118:2:118:3 | it | standalone_iterators.cpp:118:5:118:5 | call to operator+= | TAINT |
|
||||
| standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:119:7:119:8 | it | |
|
||||
| standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:120:2:120:3 | it | |
|
||||
| standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:121:7:121:8 | it | |
|
||||
| standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:122:7:122:8 | c1 | |
|
||||
| standalone_iterators.cpp:118:8:118:8 | 1 | standalone_iterators.cpp:118:2:118:3 | ref arg it | TAINT |
|
||||
| standalone_iterators.cpp:120:2:120:3 | it | standalone_iterators.cpp:120:5:120:5 | call to operator+= | |
|
||||
| standalone_iterators.cpp:120:2:120:3 | it | standalone_iterators.cpp:120:5:120:5 | call to operator+= | TAINT |
|
||||
| standalone_iterators.cpp:120:2:120:3 | ref arg it | standalone_iterators.cpp:121:7:121:8 | it | |
|
||||
| standalone_iterators.cpp:120:8:120:13 | call to source | standalone_iterators.cpp:120:2:120:3 | ref arg it | TAINT |
|
||||
| stl.h:75:8:75:8 | Unknown literal | stl.h:75:8:75:8 | constructor init of field container | TAINT |
|
||||
@@ -3655,12 +3666,12 @@
|
||||
| stl.h:402:95:402:95 | y | stl.h:403:79:403:79 | y | |
|
||||
| stl.h:402:95:402:95 | y | stl.h:403:79:403:79 | y | |
|
||||
| stl.h:402:95:402:95 | y | stl.h:403:79:403:79 | y | |
|
||||
| stl.h:403:58:403:58 | x | stl.h:403:41:403:56 | call to forward | |
|
||||
| stl.h:403:58:403:58 | x | stl.h:403:41:403:56 | call to forward | |
|
||||
| stl.h:403:58:403:58 | x | stl.h:403:41:403:56 | call to forward | |
|
||||
| stl.h:403:58:403:58 | x | stl.h:403:41:403:56 | call to forward | |
|
||||
| stl.h:403:58:403:58 | x | stl.h:403:41:403:56 | call to forward | |
|
||||
| stl.h:403:58:403:58 | x | stl.h:403:41:403:56 | call to forward | |
|
||||
| stl.h:403:58:403:58 | x | stl.h:403:41:403:56 | call to forward | TAINT |
|
||||
| stl.h:403:58:403:58 | x | stl.h:403:41:403:56 | call to forward | TAINT |
|
||||
| stl.h:403:58:403:58 | x | stl.h:403:41:403:56 | call to forward | TAINT |
|
||||
| stl.h:403:58:403:58 | x | stl.h:403:41:403:56 | call to forward | TAINT |
|
||||
| stl.h:403:58:403:58 | x | stl.h:403:41:403:56 | call to forward | TAINT |
|
||||
| stl.h:403:58:403:58 | x | stl.h:403:41:403:56 | call to forward | TAINT |
|
||||
| stl.h:403:62:403:77 | call to forward | stl.h:403:3:403:82 | call to pair | TAINT |
|
||||
| stl.h:403:62:403:77 | call to forward | stl.h:403:3:403:82 | call to pair | TAINT |
|
||||
| stl.h:403:62:403:77 | call to forward | stl.h:403:3:403:82 | call to pair | TAINT |
|
||||
@@ -3673,12 +3684,12 @@
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:3:403:82 | call to pair | TAINT |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:3:403:82 | call to pair | TAINT |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:3:403:82 | call to pair | TAINT |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:62:403:77 | call to forward | |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:62:403:77 | call to forward | |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:62:403:77 | call to forward | |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:62:403:77 | call to forward | |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:62:403:77 | call to forward | |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:62:403:77 | call to forward | |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:62:403:77 | call to forward | TAINT |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:62:403:77 | call to forward | TAINT |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:62:403:77 | call to forward | TAINT |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:62:403:77 | call to forward | TAINT |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:62:403:77 | call to forward | TAINT |
|
||||
| stl.h:403:79:403:79 | y | stl.h:403:62:403:77 | call to forward | TAINT |
|
||||
| string.cpp:25:12:25:17 | call to source | string.cpp:29:7:29:7 | a | |
|
||||
| string.cpp:26:16:26:20 | 123 | string.cpp:26:16:26:21 | call to basic_string | TAINT |
|
||||
| string.cpp:26:16:26:21 | call to basic_string | string.cpp:30:7:30:7 | b | |
|
||||
@@ -4231,13 +4242,13 @@
|
||||
| string.cpp:407:9:407:10 | i6 | string.cpp:407:8:407:8 | call to operator* | TAINT |
|
||||
| string.cpp:408:8:408:9 | i2 | string.cpp:408:3:408:9 | ... = ... | |
|
||||
| string.cpp:408:8:408:9 | i2 | string.cpp:409:10:409:11 | i7 | |
|
||||
| string.cpp:409:10:409:11 | i7 | string.cpp:409:12:409:12 | call to operator+= | |
|
||||
| string.cpp:409:10:409:11 | i7 | string.cpp:409:12:409:12 | call to operator+= | TAINT |
|
||||
| string.cpp:409:12:409:12 | call to operator+= | string.cpp:409:8:409:8 | call to operator* | TAINT |
|
||||
| string.cpp:409:12:409:12 | ref arg call to operator+= | string.cpp:409:10:409:11 | ref arg i7 | TAINT |
|
||||
| string.cpp:409:14:409:14 | 1 | string.cpp:409:10:409:11 | ref arg i7 | TAINT |
|
||||
| string.cpp:410:8:410:9 | i2 | string.cpp:410:3:410:9 | ... = ... | |
|
||||
| string.cpp:410:8:410:9 | i2 | string.cpp:411:10:411:11 | i8 | |
|
||||
| string.cpp:411:10:411:11 | i8 | string.cpp:411:12:411:12 | call to operator-= | |
|
||||
| string.cpp:411:10:411:11 | i8 | string.cpp:411:12:411:12 | call to operator-= | TAINT |
|
||||
| string.cpp:411:12:411:12 | call to operator-= | string.cpp:411:8:411:8 | call to operator* | TAINT |
|
||||
| string.cpp:411:12:411:12 | ref arg call to operator-= | string.cpp:411:10:411:11 | ref arg i8 | TAINT |
|
||||
| string.cpp:411:14:411:14 | 1 | string.cpp:411:10:411:11 | ref arg i8 | TAINT |
|
||||
@@ -4652,7 +4663,7 @@
|
||||
| stringstream.cpp:33:7:33:9 | ref arg ss3 | stringstream.cpp:39:7:39:9 | ss3 | |
|
||||
| stringstream.cpp:33:7:33:9 | ref arg ss3 | stringstream.cpp:44:7:44:9 | ss3 | |
|
||||
| stringstream.cpp:33:7:33:9 | ss3 | stringstream.cpp:33:11:33:11 | call to operator<< | |
|
||||
| stringstream.cpp:33:11:33:11 | call to operator<< | stringstream.cpp:33:20:33:20 | call to operator<< | |
|
||||
| stringstream.cpp:33:11:33:11 | call to operator<< | stringstream.cpp:33:20:33:20 | call to operator<< | TAINT |
|
||||
| stringstream.cpp:33:11:33:11 | ref arg call to operator<< | stringstream.cpp:33:7:33:9 | ref arg ss3 | TAINT |
|
||||
| stringstream.cpp:33:14:33:18 | 123 | stringstream.cpp:33:7:33:9 | ref arg ss3 | TAINT |
|
||||
| stringstream.cpp:33:14:33:18 | 123 | stringstream.cpp:33:11:33:11 | call to operator<< | TAINT |
|
||||
@@ -4661,7 +4672,7 @@
|
||||
| stringstream.cpp:34:7:34:9 | ref arg ss4 | stringstream.cpp:40:7:40:9 | ss4 | |
|
||||
| stringstream.cpp:34:7:34:9 | ref arg ss4 | stringstream.cpp:45:7:45:9 | ss4 | |
|
||||
| stringstream.cpp:34:7:34:9 | ss4 | stringstream.cpp:34:11:34:11 | call to operator<< | |
|
||||
| stringstream.cpp:34:11:34:11 | call to operator<< | stringstream.cpp:34:23:34:23 | call to operator<< | |
|
||||
| stringstream.cpp:34:11:34:11 | call to operator<< | stringstream.cpp:34:23:34:23 | call to operator<< | TAINT |
|
||||
| stringstream.cpp:34:11:34:11 | ref arg call to operator<< | stringstream.cpp:34:7:34:9 | ref arg ss4 | TAINT |
|
||||
| stringstream.cpp:34:14:34:19 | call to source | stringstream.cpp:34:7:34:9 | ref arg ss4 | TAINT |
|
||||
| stringstream.cpp:34:14:34:19 | call to source | stringstream.cpp:34:11:34:11 | call to operator<< | TAINT |
|
||||
@@ -4942,7 +4953,7 @@
|
||||
| stringstream.cpp:147:7:147:9 | ref arg ss2 | stringstream.cpp:179:7:179:9 | ss2 | |
|
||||
| stringstream.cpp:147:7:147:9 | ss2 | stringstream.cpp:147:11:147:11 | call to operator>> | |
|
||||
| stringstream.cpp:147:7:147:9 | ss2 | stringstream.cpp:147:14:147:15 | ref arg s3 | TAINT |
|
||||
| stringstream.cpp:147:11:147:11 | call to operator>> | stringstream.cpp:147:17:147:17 | call to operator>> | |
|
||||
| stringstream.cpp:147:11:147:11 | call to operator>> | stringstream.cpp:147:17:147:17 | call to operator>> | TAINT |
|
||||
| stringstream.cpp:147:11:147:11 | call to operator>> | stringstream.cpp:147:20:147:21 | ref arg s4 | TAINT |
|
||||
| stringstream.cpp:147:11:147:11 | ref arg call to operator>> | stringstream.cpp:147:7:147:9 | ref arg ss2 | TAINT |
|
||||
| stringstream.cpp:147:14:147:15 | ref arg s3 | stringstream.cpp:150:7:150:8 | s3 | |
|
||||
@@ -4974,7 +4985,7 @@
|
||||
| stringstream.cpp:155:7:155:9 | ref arg ss2 | stringstream.cpp:179:7:179:9 | ss2 | |
|
||||
| stringstream.cpp:155:7:155:9 | ss2 | stringstream.cpp:155:11:155:11 | call to operator>> | |
|
||||
| stringstream.cpp:155:7:155:9 | ss2 | stringstream.cpp:155:14:155:15 | ref arg b3 | TAINT |
|
||||
| stringstream.cpp:155:11:155:11 | call to operator>> | stringstream.cpp:155:17:155:17 | call to operator>> | |
|
||||
| stringstream.cpp:155:11:155:11 | call to operator>> | stringstream.cpp:155:17:155:17 | call to operator>> | TAINT |
|
||||
| stringstream.cpp:155:11:155:11 | call to operator>> | stringstream.cpp:155:20:155:21 | ref arg b4 | TAINT |
|
||||
| stringstream.cpp:155:11:155:11 | ref arg call to operator>> | stringstream.cpp:155:7:155:9 | ref arg ss2 | TAINT |
|
||||
| stringstream.cpp:155:14:155:15 | ref arg b3 | stringstream.cpp:158:7:158:8 | b3 | |
|
||||
@@ -5296,7 +5307,7 @@
|
||||
| stringstream.cpp:245:15:245:17 | ss1 | stringstream.cpp:245:7:245:13 | call to getline | |
|
||||
| stringstream.cpp:245:15:245:17 | ss1 | stringstream.cpp:245:20:245:21 | ref arg s6 | TAINT |
|
||||
| stringstream.cpp:245:20:245:21 | ref arg s6 | stringstream.cpp:248:7:248:8 | s6 | |
|
||||
| stringstream.cpp:250:15:250:21 | call to getline | stringstream.cpp:250:7:250:13 | call to getline | |
|
||||
| stringstream.cpp:250:15:250:21 | call to getline | stringstream.cpp:250:7:250:13 | call to getline | TAINT |
|
||||
| stringstream.cpp:250:15:250:21 | call to getline | stringstream.cpp:250:33:250:34 | ref arg s8 | TAINT |
|
||||
| stringstream.cpp:250:15:250:21 | ref arg call to getline | stringstream.cpp:250:23:250:25 | ref arg ss2 | TAINT |
|
||||
| stringstream.cpp:250:23:250:25 | ss2 | stringstream.cpp:250:15:250:21 | call to getline | |
|
||||
@@ -5500,7 +5511,7 @@
|
||||
| swap1.cpp:100:9:100:17 | ref arg call to move | swap1.cpp:103:10:103:10 | x | |
|
||||
| swap1.cpp:100:19:100:19 | x | swap1.cpp:100:5:100:5 | ref arg y | TAINT |
|
||||
| swap1.cpp:100:19:100:19 | x | swap1.cpp:100:7:100:7 | call to operator= | TAINT |
|
||||
| swap1.cpp:100:19:100:19 | x | swap1.cpp:100:9:100:17 | call to move | |
|
||||
| swap1.cpp:100:19:100:19 | x | swap1.cpp:100:9:100:17 | call to move | TAINT |
|
||||
| swap1.cpp:108:23:108:31 | move_from | swap1.cpp:109:5:109:13 | move_from | |
|
||||
| swap1.cpp:108:23:108:31 | move_from | swap1.cpp:111:10:111:18 | move_from | |
|
||||
| swap1.cpp:108:23:108:31 | move_from | swap1.cpp:113:41:113:49 | move_from | |
|
||||
@@ -5513,7 +5524,7 @@
|
||||
| swap1.cpp:113:31:113:39 | call to move | swap1.cpp:113:31:113:51 | call to Class | TAINT |
|
||||
| swap1.cpp:113:31:113:39 | ref arg call to move | swap1.cpp:113:41:113:49 | move_from [inner post update] | |
|
||||
| swap1.cpp:113:31:113:51 | call to Class | swap1.cpp:115:10:115:16 | move_to | |
|
||||
| swap1.cpp:113:41:113:49 | move_from | swap1.cpp:113:31:113:39 | call to move | |
|
||||
| swap1.cpp:113:41:113:49 | move_from | swap1.cpp:113:31:113:39 | call to move | TAINT |
|
||||
| swap1.cpp:113:41:113:49 | move_from | swap1.cpp:113:31:113:51 | call to Class | |
|
||||
| swap1.cpp:120:23:120:23 | x | swap1.cpp:122:5:122:5 | x | |
|
||||
| swap1.cpp:120:23:120:23 | x | swap1.cpp:124:10:124:10 | x | |
|
||||
@@ -5547,7 +5558,7 @@
|
||||
| swap1.cpp:142:5:142:5 | ref arg y | swap1.cpp:144:10:144:10 | y | |
|
||||
| swap1.cpp:142:19:142:27 | ref arg call to move | swap1.cpp:142:29:142:29 | x [inner post update] | |
|
||||
| swap1.cpp:142:19:142:27 | ref arg call to move | swap1.cpp:145:10:145:10 | x | |
|
||||
| swap1.cpp:142:29:142:29 | x | swap1.cpp:142:19:142:27 | call to move | |
|
||||
| swap1.cpp:142:29:142:29 | x | swap1.cpp:142:19:142:27 | call to move | TAINT |
|
||||
| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:17:14:17 | t | |
|
||||
| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:17:14:17 | t | |
|
||||
| swap2.cpp:14:17:14:17 | t | swap2.cpp:14:56:14:56 | t | |
|
||||
@@ -5679,7 +5690,7 @@
|
||||
| swap2.cpp:100:9:100:17 | ref arg call to move | swap2.cpp:103:10:103:10 | x | |
|
||||
| swap2.cpp:100:19:100:19 | x | swap2.cpp:100:5:100:5 | ref arg y | TAINT |
|
||||
| swap2.cpp:100:19:100:19 | x | swap2.cpp:100:7:100:7 | call to operator= | TAINT |
|
||||
| swap2.cpp:100:19:100:19 | x | swap2.cpp:100:9:100:17 | call to move | |
|
||||
| swap2.cpp:100:19:100:19 | x | swap2.cpp:100:9:100:17 | call to move | TAINT |
|
||||
| swap2.cpp:108:23:108:31 | move_from | swap2.cpp:109:5:109:13 | move_from | |
|
||||
| swap2.cpp:108:23:108:31 | move_from | swap2.cpp:111:10:111:18 | move_from | |
|
||||
| swap2.cpp:108:23:108:31 | move_from | swap2.cpp:113:41:113:49 | move_from | |
|
||||
@@ -5692,7 +5703,7 @@
|
||||
| swap2.cpp:113:31:113:39 | call to move | swap2.cpp:113:31:113:51 | call to Class | TAINT |
|
||||
| swap2.cpp:113:31:113:39 | ref arg call to move | swap2.cpp:113:41:113:49 | move_from [inner post update] | |
|
||||
| swap2.cpp:113:31:113:51 | call to Class | swap2.cpp:115:10:115:16 | move_to | |
|
||||
| swap2.cpp:113:41:113:49 | move_from | swap2.cpp:113:31:113:39 | call to move | |
|
||||
| swap2.cpp:113:41:113:49 | move_from | swap2.cpp:113:31:113:39 | call to move | TAINT |
|
||||
| swap2.cpp:113:41:113:49 | move_from | swap2.cpp:113:31:113:51 | call to Class | |
|
||||
| swap2.cpp:120:23:120:23 | x | swap2.cpp:122:5:122:5 | x | |
|
||||
| swap2.cpp:120:23:120:23 | x | swap2.cpp:124:10:124:10 | x | |
|
||||
@@ -5726,7 +5737,7 @@
|
||||
| swap2.cpp:142:5:142:5 | ref arg y | swap2.cpp:144:10:144:10 | y | |
|
||||
| swap2.cpp:142:19:142:27 | ref arg call to move | swap2.cpp:142:29:142:29 | x [inner post update] | |
|
||||
| swap2.cpp:142:19:142:27 | ref arg call to move | swap2.cpp:145:10:145:10 | x | |
|
||||
| swap2.cpp:142:29:142:29 | x | swap2.cpp:142:19:142:27 | call to move | |
|
||||
| swap2.cpp:142:29:142:29 | x | swap2.cpp:142:19:142:27 | call to move | TAINT |
|
||||
| taint.cpp:4:27:4:33 | source1 | taint.cpp:6:13:6:19 | source1 | |
|
||||
| taint.cpp:4:40:4:45 | clean1 | taint.cpp:5:8:5:13 | clean1 | |
|
||||
| taint.cpp:4:40:4:45 | clean1 | taint.cpp:6:3:6:8 | clean1 | |
|
||||
@@ -7950,7 +7961,7 @@
|
||||
| vector.cpp:527:9:527:10 | ref arg it | vector.cpp:529:9:529:10 | it | |
|
||||
| vector.cpp:527:9:527:10 | ref arg it | vector.cpp:530:3:530:4 | it | |
|
||||
| vector.cpp:527:9:527:10 | ref arg it | vector.cpp:531:9:531:10 | it | |
|
||||
| vector.cpp:528:3:528:4 | it | vector.cpp:528:6:528:6 | call to operator+= | |
|
||||
| vector.cpp:528:3:528:4 | it | vector.cpp:528:6:528:6 | call to operator+= | TAINT |
|
||||
| vector.cpp:528:3:528:4 | ref arg it | vector.cpp:529:9:529:10 | it | |
|
||||
| vector.cpp:528:3:528:4 | ref arg it | vector.cpp:530:3:530:4 | it | |
|
||||
| vector.cpp:528:3:528:4 | ref arg it | vector.cpp:531:9:531:10 | it | |
|
||||
@@ -7958,7 +7969,7 @@
|
||||
| vector.cpp:529:9:529:10 | it | vector.cpp:529:8:529:8 | call to operator* | TAINT |
|
||||
| vector.cpp:529:9:529:10 | ref arg it | vector.cpp:530:3:530:4 | it | |
|
||||
| vector.cpp:529:9:529:10 | ref arg it | vector.cpp:531:9:531:10 | it | |
|
||||
| vector.cpp:530:3:530:4 | it | vector.cpp:530:6:530:6 | call to operator+= | |
|
||||
| vector.cpp:530:3:530:4 | it | vector.cpp:530:6:530:6 | call to operator+= | TAINT |
|
||||
| vector.cpp:530:3:530:4 | ref arg it | vector.cpp:531:9:531:10 | it | |
|
||||
| vector.cpp:530:9:530:14 | call to source | vector.cpp:530:3:530:4 | ref arg it | TAINT |
|
||||
| vector.cpp:531:9:531:10 | it | vector.cpp:531:8:531:8 | call to operator* | TAINT |
|
||||
|
||||
@@ -9,7 +9,7 @@ template<typename T> void sink(std::unique_ptr<T>&);
|
||||
|
||||
void test_make_shared() {
|
||||
std::shared_ptr<int> p = std::make_shared<int>(source());
|
||||
sink(*p); // $ ast MISSING: ir
|
||||
sink(*p); // $ ast,ir
|
||||
sink(p); // $ ast,ir
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ void test_make_shared_array() {
|
||||
|
||||
void test_make_unique() {
|
||||
std::unique_ptr<int> p = std::make_unique<int>(source());
|
||||
sink(*p); // $ ast MISSING: ir
|
||||
sink(*p); // $ ast,ir
|
||||
sink(p); // $ ast,ir
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ void taint_x(A* pa) {
|
||||
void reverse_taint_smart_pointer() {
|
||||
std::unique_ptr<A> p = std::unique_ptr<A>(new A);
|
||||
taint_x(p.get());
|
||||
sink(p->x); // $ ast MISSING: ir
|
||||
sink(p->x); // $ ast,ir
|
||||
}
|
||||
|
||||
struct C {
|
||||
|
||||
@@ -5,7 +5,16 @@ private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||
private predicate ignoreAllocation(string name) {
|
||||
name = "i" or
|
||||
name = "p" or
|
||||
name = "q"
|
||||
name = "q" or
|
||||
name = "s" or
|
||||
name = "t" or
|
||||
name = "?{AllAliased}"
|
||||
}
|
||||
|
||||
private predicate ignoreFile(File file) {
|
||||
// Ignore standard headers.
|
||||
file.getBaseName() = ["memory.h", "type_traits.h", "utility.h"] or
|
||||
not file.fromSource()
|
||||
}
|
||||
|
||||
module Raw {
|
||||
@@ -29,7 +38,8 @@ module Raw {
|
||||
not ignoreAllocation(memLocation.getAllocation().getAllocationString()) and
|
||||
value = memLocation.toString() and
|
||||
element = instr.toString() and
|
||||
location = instr.getLocation()
|
||||
location = instr.getLocation() and
|
||||
not ignoreFile(location.getFile())
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -52,13 +62,14 @@ module UnaliasedSSA {
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(Instruction instr, MemoryLocation memLocation |
|
||||
memLocation = getAMemoryAccess(instr) and
|
||||
not memLocation instanceof AliasedVirtualVariable and
|
||||
not memLocation.getVirtualVariable() instanceof AliasedVirtualVariable and
|
||||
not memLocation instanceof AllNonLocalMemory and
|
||||
tag = "ussa" and
|
||||
not ignoreAllocation(memLocation.getAllocation().getAllocationString()) and
|
||||
value = memLocation.toString() and
|
||||
element = instr.toString() and
|
||||
location = instr.getLocation()
|
||||
location = instr.getLocation() and
|
||||
not ignoreFile(location.getFile())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
33
cpp/ql/test/library-tests/ir/points_to/smart_pointer.cpp
Normal file
33
cpp/ql/test/library-tests/ir/points_to/smart_pointer.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "../../../include/memory.h"
|
||||
#include "../../../include/utility.h"
|
||||
|
||||
using std::shared_ptr;
|
||||
using std::unique_ptr;
|
||||
|
||||
struct S {
|
||||
int x;
|
||||
};
|
||||
|
||||
void unique_ptr_init(S s) {
|
||||
unique_ptr<S> p(new S); //$ussa=dynamic{1}
|
||||
int i = (*p).x; //$ussa=dynamic{1}[0..4)<int>
|
||||
*p = s; //$ussa=dynamic{1}[0..4)<S>
|
||||
unique_ptr<S> q = std::move(p);
|
||||
*(q.get()) = s; //$ussa=dynamic{1}[0..4)<S>
|
||||
shared_ptr<S> t(std::move(q));
|
||||
t->x = 5; //$ussa=dynamic{1}[0..4)<int>
|
||||
*t = s; //$ussa=dynamic{1}[0..4)<S>
|
||||
*(t.get()) = s; //$ussa=dynamic{1}[0..4)<S>
|
||||
}
|
||||
|
||||
void shared_ptr_init(S s) {
|
||||
shared_ptr<S> p(new S); //$ussa=dynamic{1}
|
||||
int i = (*p).x; //$ussa=dynamic{1}[0..4)<int>
|
||||
*p = s; //$ussa=dynamic{1}[0..4)<S>
|
||||
shared_ptr<S> q = std::move(p);
|
||||
*(q.get()) = s; //$ussa=dynamic{1}[0..4)<S>
|
||||
shared_ptr<S> t(q);
|
||||
t->x = 5; //$ussa=dynamic{1}[0..4)<int>
|
||||
*t = s; //$ussa=dynamic{1}[0..4)<S>
|
||||
*(t.get()) = s; //$ussa=dynamic{1}[0..4)<S>
|
||||
}
|
||||
Reference in New Issue
Block a user