Skip to content

Commit 5085e46

Browse files
author
Dave Bartolomeo
committed
C++: Allow alias propagation to/from side effects (part 1)
1 parent 01a9531 commit 5085e46

File tree

3 files changed

+204
-201
lines changed

3 files changed

+204
-201
lines changed

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

Lines changed: 68 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ private predicate operandIsConsumedWithoutEscaping(Operand operand) {
3434

3535
private predicate operandEscapesDomain(Operand operand) {
3636
not operandIsConsumedWithoutEscaping(operand) and
37-
not operandIsPropagated(operand, _) and
37+
not operandIsPropagated(operand, _, _) and
3838
not isArgumentForParameter(_, operand, _) and
3939
not isOnlyEscapesViaReturnArgument(operand) and
4040
not operand.getUse() instanceof ReturnValueInstruction and
@@ -69,67 +69,66 @@ IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
6969
}
7070

7171
/**
72-
* Holds if any address held in operand `tag` of instruction `instr` is
73-
* propagated to the result of `instr`, offset by the number of bits in
74-
* `bitOffset`. If the address is propagated, but the offset is not known to be
75-
* a constant, then `bitOffset` is unknown.
72+
* Holds if any address held in operand `operand` is propagated to the result of `instr`, offset by
73+
* the number of bits in `bitOffset`. If the address is propagated, but the offset is not known to
74+
* be a constant, then `bitOffset` is `unknown()`.
7675
*/
77-
private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
78-
exists(Instruction instr |
79-
instr = operand.getUse() and
80-
(
81-
// Converting to a non-virtual base class adds the offset of the base class.
82-
exists(ConvertToNonVirtualBaseInstruction convert |
83-
convert = instr and
84-
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
85-
)
86-
or
87-
// Conversion using dynamic_cast results in an unknown offset
88-
instr instanceof CheckedConvertOrNullInstruction and
89-
bitOffset = Ints::unknown()
90-
or
91-
// Converting to a derived class subtracts the offset of the base class.
92-
exists(ConvertToDerivedInstruction convert |
93-
convert = instr and
94-
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
95-
)
96-
or
97-
// Converting to a virtual base class adds an unknown offset.
98-
instr instanceof ConvertToVirtualBaseInstruction and
99-
bitOffset = Ints::unknown()
100-
or
101-
// Conversion to another pointer type propagates the source address.
102-
exists(ConvertInstruction convert, IRType resultType |
103-
convert = instr and
104-
resultType = convert.getResultIRType() and
105-
resultType instanceof IRAddressType and
106-
bitOffset = 0
107-
)
108-
or
109-
// Adding an integer to or subtracting an integer from a pointer propagates
110-
// the address with an offset.
111-
exists(PointerOffsetInstruction ptrOffset |
112-
ptrOffset = instr and
113-
operand = ptrOffset.getLeftOperand() and
114-
bitOffset = getPointerBitOffset(ptrOffset)
115-
)
116-
or
117-
// Computing a field address from a pointer propagates the address plus the
118-
// offset of the field.
119-
bitOffset = Language::getFieldBitOffset(instr.(FieldAddressInstruction).getField())
120-
or
121-
// A copy propagates the source value.
122-
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
123-
or
124-
// Some functions are known to propagate an argument
125-
isAlwaysReturnedArgument(operand) and bitOffset = 0
76+
private predicate operandIsPropagated(Operand operand, IntValue bitOffset, Instruction instr) {
77+
instr = operand.getUse() and
78+
(
79+
// Converting to a non-virtual base class adds the offset of the base class.
80+
exists(ConvertToNonVirtualBaseInstruction convert |
81+
convert = instr and
82+
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
12683
)
84+
or
85+
// Conversion using dynamic_cast results in an unknown offset
86+
instr instanceof CheckedConvertOrNullInstruction and
87+
bitOffset = Ints::unknown()
88+
or
89+
// Converting to a derived class subtracts the offset of the base class.
90+
exists(ConvertToDerivedInstruction convert |
91+
convert = instr and
92+
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
93+
)
94+
or
95+
// Converting to a virtual base class adds an unknown offset.
96+
instr instanceof ConvertToVirtualBaseInstruction and
97+
bitOffset = Ints::unknown()
98+
or
99+
// Conversion to another pointer type propagates the source address.
100+
exists(ConvertInstruction convert, IRType resultType |
101+
convert = instr and
102+
resultType = convert.getResultIRType() and
103+
resultType instanceof IRAddressType and
104+
bitOffset = 0
105+
)
106+
or
107+
// Adding an integer to or subtracting an integer from a pointer propagates
108+
// the address with an offset.
109+
exists(PointerOffsetInstruction ptrOffset |
110+
ptrOffset = instr and
111+
operand = ptrOffset.getLeftOperand() and
112+
bitOffset = getPointerBitOffset(ptrOffset)
113+
)
114+
or
115+
// Computing a field address from a pointer propagates the address plus the
116+
// offset of the field.
117+
bitOffset = Language::getFieldBitOffset(instr.(FieldAddressInstruction).getField())
118+
or
119+
// A copy propagates the source value.
120+
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
121+
or
122+
// Some functions are known to propagate an argument
123+
isAlwaysReturnedArgument(operand) and bitOffset = 0
127124
)
128125
}
129126

130127
private predicate operandEscapesNonReturn(Operand operand) {
131-
// The address is propagated to the result of the instruction, and that result itself is returned
132-
operandIsPropagated(operand, _) and resultEscapesNonReturn(operand.getUse())
128+
exists(Instruction instr |
129+
// The address is propagated to the result of the instruction, and that result itself is returned
130+
operandIsPropagated(operand, _, instr) and resultEscapesNonReturn(instr)
131+
)
133132
or
134133
// The operand is used in a function call which returns it, and the return value is then returned
135134
exists(CallInstruction ci, Instruction init |
@@ -151,9 +150,11 @@ private predicate operandEscapesNonReturn(Operand operand) {
151150
}
152151

153152
private predicate operandMayReachReturn(Operand operand) {
154-
// The address is propagated to the result of the instruction, and that result itself is returned
155-
operandIsPropagated(operand, _) and
156-
resultMayReachReturn(operand.getUse())
153+
exists(Instruction instr |
154+
// The address is propagated to the result of the instruction, and that result itself is returned
155+
operandIsPropagated(operand, _, instr) and
156+
resultMayReachReturn(instr)
157+
)
157158
or
158159
// The operand is used in a function call which returns it, and the return value is then returned
159160
exists(CallInstruction ci, Instruction init |
@@ -173,9 +174,9 @@ private predicate operandMayReachReturn(Operand operand) {
173174

174175
private predicate operandReturned(Operand operand, IntValue bitOffset) {
175176
// The address is propagated to the result of the instruction, and that result itself is returned
176-
exists(IntValue bitOffset1, IntValue bitOffset2 |
177-
operandIsPropagated(operand, bitOffset1) and
178-
resultReturned(operand.getUse(), bitOffset2) and
177+
exists(Instruction instr, IntValue bitOffset1, IntValue bitOffset2 |
178+
operandIsPropagated(operand, bitOffset1, instr) and
179+
resultReturned(instr, bitOffset2) and
179180
bitOffset = Ints::add(bitOffset1, bitOffset2)
180181
)
181182
or
@@ -270,12 +271,13 @@ predicate allocationEscapes(Configuration::Allocation allocation) {
270271
/**
271272
* Equivalent to `operandIsPropagated()`, but includes interprocedural propagation.
272273
*/
273-
private predicate operandIsPropagatedIncludingByCall(Operand operand, IntValue bitOffset) {
274-
operandIsPropagated(operand, bitOffset)
274+
private predicate operandIsPropagatedIncludingByCall(Operand operand, IntValue bitOffset, Instruction instr) {
275+
operandIsPropagated(operand, bitOffset, instr)
275276
or
276277
exists(CallInstruction call, Instruction init |
277278
isArgumentForParameter(call, operand, init) and
278-
resultReturned(init, bitOffset)
279+
resultReturned(init, bitOffset) and
280+
instr = call
279281
)
280282
}
281283

@@ -292,8 +294,7 @@ private predicate hasBaseAndOffset(AddressOperand addrOperand, Instruction base,
292294
// We already have an offset from `middle`.
293295
hasBaseAndOffset(addrOperand, middle, previousBitOffset) and
294296
// `middle` is propagated from `base`.
295-
middleOperand = middle.getAnOperand() and
296-
operandIsPropagatedIncludingByCall(middleOperand, additionalBitOffset) and
297+
operandIsPropagatedIncludingByCall(middleOperand, additionalBitOffset, middle) and
297298
base = middleOperand.getDef() and
298299
bitOffset = Ints::add(previousBitOffset, additionalBitOffset)
299300
)

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

Lines changed: 68 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ private predicate operandIsConsumedWithoutEscaping(Operand operand) {
3434

3535
private predicate operandEscapesDomain(Operand operand) {
3636
not operandIsConsumedWithoutEscaping(operand) and
37-
not operandIsPropagated(operand, _) and
37+
not operandIsPropagated(operand, _, _) and
3838
not isArgumentForParameter(_, operand, _) and
3939
not isOnlyEscapesViaReturnArgument(operand) and
4040
not operand.getUse() instanceof ReturnValueInstruction and
@@ -69,67 +69,66 @@ IntValue getPointerBitOffset(PointerOffsetInstruction instr) {
6969
}
7070

7171
/**
72-
* Holds if any address held in operand `tag` of instruction `instr` is
73-
* propagated to the result of `instr`, offset by the number of bits in
74-
* `bitOffset`. If the address is propagated, but the offset is not known to be
75-
* a constant, then `bitOffset` is unknown.
72+
* Holds if any address held in operand `operand` is propagated to the result of `instr`, offset by
73+
* the number of bits in `bitOffset`. If the address is propagated, but the offset is not known to
74+
* be a constant, then `bitOffset` is `unknown()`.
7675
*/
77-
private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
78-
exists(Instruction instr |
79-
instr = operand.getUse() and
80-
(
81-
// Converting to a non-virtual base class adds the offset of the base class.
82-
exists(ConvertToNonVirtualBaseInstruction convert |
83-
convert = instr and
84-
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
85-
)
86-
or
87-
// Conversion using dynamic_cast results in an unknown offset
88-
instr instanceof CheckedConvertOrNullInstruction and
89-
bitOffset = Ints::unknown()
90-
or
91-
// Converting to a derived class subtracts the offset of the base class.
92-
exists(ConvertToDerivedInstruction convert |
93-
convert = instr and
94-
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
95-
)
96-
or
97-
// Converting to a virtual base class adds an unknown offset.
98-
instr instanceof ConvertToVirtualBaseInstruction and
99-
bitOffset = Ints::unknown()
100-
or
101-
// Conversion to another pointer type propagates the source address.
102-
exists(ConvertInstruction convert, IRType resultType |
103-
convert = instr and
104-
resultType = convert.getResultIRType() and
105-
resultType instanceof IRAddressType and
106-
bitOffset = 0
107-
)
108-
or
109-
// Adding an integer to or subtracting an integer from a pointer propagates
110-
// the address with an offset.
111-
exists(PointerOffsetInstruction ptrOffset |
112-
ptrOffset = instr and
113-
operand = ptrOffset.getLeftOperand() and
114-
bitOffset = getPointerBitOffset(ptrOffset)
115-
)
116-
or
117-
// Computing a field address from a pointer propagates the address plus the
118-
// offset of the field.
119-
bitOffset = Language::getFieldBitOffset(instr.(FieldAddressInstruction).getField())
120-
or
121-
// A copy propagates the source value.
122-
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
123-
or
124-
// Some functions are known to propagate an argument
125-
isAlwaysReturnedArgument(operand) and bitOffset = 0
76+
private predicate operandIsPropagated(Operand operand, IntValue bitOffset, Instruction instr) {
77+
instr = operand.getUse() and
78+
(
79+
// Converting to a non-virtual base class adds the offset of the base class.
80+
exists(ConvertToNonVirtualBaseInstruction convert |
81+
convert = instr and
82+
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
12683
)
84+
or
85+
// Conversion using dynamic_cast results in an unknown offset
86+
instr instanceof CheckedConvertOrNullInstruction and
87+
bitOffset = Ints::unknown()
88+
or
89+
// Converting to a derived class subtracts the offset of the base class.
90+
exists(ConvertToDerivedInstruction convert |
91+
convert = instr and
92+
bitOffset = Ints::neg(Ints::mul(convert.getDerivation().getByteOffset(), 8))
93+
)
94+
or
95+
// Converting to a virtual base class adds an unknown offset.
96+
instr instanceof ConvertToVirtualBaseInstruction and
97+
bitOffset = Ints::unknown()
98+
or
99+
// Conversion to another pointer type propagates the source address.
100+
exists(ConvertInstruction convert, IRType resultType |
101+
convert = instr and
102+
resultType = convert.getResultIRType() and
103+
resultType instanceof IRAddressType and
104+
bitOffset = 0
105+
)
106+
or
107+
// Adding an integer to or subtracting an integer from a pointer propagates
108+
// the address with an offset.
109+
exists(PointerOffsetInstruction ptrOffset |
110+
ptrOffset = instr and
111+
operand = ptrOffset.getLeftOperand() and
112+
bitOffset = getPointerBitOffset(ptrOffset)
113+
)
114+
or
115+
// Computing a field address from a pointer propagates the address plus the
116+
// offset of the field.
117+
bitOffset = Language::getFieldBitOffset(instr.(FieldAddressInstruction).getField())
118+
or
119+
// A copy propagates the source value.
120+
operand = instr.(CopyInstruction).getSourceValueOperand() and bitOffset = 0
121+
or
122+
// Some functions are known to propagate an argument
123+
isAlwaysReturnedArgument(operand) and bitOffset = 0
127124
)
128125
}
129126

130127
private predicate operandEscapesNonReturn(Operand operand) {
131-
// The address is propagated to the result of the instruction, and that result itself is returned
132-
operandIsPropagated(operand, _) and resultEscapesNonReturn(operand.getUse())
128+
exists(Instruction instr |
129+
// The address is propagated to the result of the instruction, and that result itself is returned
130+
operandIsPropagated(operand, _, instr) and resultEscapesNonReturn(instr)
131+
)
133132
or
134133
// The operand is used in a function call which returns it, and the return value is then returned
135134
exists(CallInstruction ci, Instruction init |
@@ -151,9 +150,11 @@ private predicate operandEscapesNonReturn(Operand operand) {
151150
}
152151

153152
private predicate operandMayReachReturn(Operand operand) {
154-
// The address is propagated to the result of the instruction, and that result itself is returned
155-
operandIsPropagated(operand, _) and
156-
resultMayReachReturn(operand.getUse())
153+
exists(Instruction instr |
154+
// The address is propagated to the result of the instruction, and that result itself is returned
155+
operandIsPropagated(operand, _, instr) and
156+
resultMayReachReturn(instr)
157+
)
157158
or
158159
// The operand is used in a function call which returns it, and the return value is then returned
159160
exists(CallInstruction ci, Instruction init |
@@ -173,9 +174,9 @@ private predicate operandMayReachReturn(Operand operand) {
173174

174175
private predicate operandReturned(Operand operand, IntValue bitOffset) {
175176
// The address is propagated to the result of the instruction, and that result itself is returned
176-
exists(IntValue bitOffset1, IntValue bitOffset2 |
177-
operandIsPropagated(operand, bitOffset1) and
178-
resultReturned(operand.getUse(), bitOffset2) and
177+
exists(Instruction instr, IntValue bitOffset1, IntValue bitOffset2 |
178+
operandIsPropagated(operand, bitOffset1, instr) and
179+
resultReturned(instr, bitOffset2) and
179180
bitOffset = Ints::add(bitOffset1, bitOffset2)
180181
)
181182
or
@@ -270,12 +271,13 @@ predicate allocationEscapes(Configuration::Allocation allocation) {
270271
/**
271272
* Equivalent to `operandIsPropagated()`, but includes interprocedural propagation.
272273
*/
273-
private predicate operandIsPropagatedIncludingByCall(Operand operand, IntValue bitOffset) {
274-
operandIsPropagated(operand, bitOffset)
274+
private predicate operandIsPropagatedIncludingByCall(Operand operand, IntValue bitOffset, Instruction instr) {
275+
operandIsPropagated(operand, bitOffset, instr)
275276
or
276277
exists(CallInstruction call, Instruction init |
277278
isArgumentForParameter(call, operand, init) and
278-
resultReturned(init, bitOffset)
279+
resultReturned(init, bitOffset) and
280+
instr = call
279281
)
280282
}
281283

@@ -292,8 +294,7 @@ private predicate hasBaseAndOffset(AddressOperand addrOperand, Instruction base,
292294
// We already have an offset from `middle`.
293295
hasBaseAndOffset(addrOperand, middle, previousBitOffset) and
294296
// `middle` is propagated from `base`.
295-
middleOperand = middle.getAnOperand() and
296-
operandIsPropagatedIncludingByCall(middleOperand, additionalBitOffset) and
297+
operandIsPropagatedIncludingByCall(middleOperand, additionalBitOffset, middle) and
297298
base = middleOperand.getDef() and
298299
bitOffset = Ints::add(previousBitOffset, additionalBitOffset)
299300
)

0 commit comments

Comments
 (0)