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

Skip to content

Commit 64480c2

Browse files
author
Dave Bartolomeo
authored
Merge pull request #1999 from jbj/ir-copy-unloaded-result
C++: Make sure there's a Instruction for each Expr
2 parents 2c88848 + 76a3db9 commit 64480c2

11 files changed

Lines changed: 1489 additions & 1171 deletions

File tree

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,23 @@ private module Cached {
5151
Expr getInstructionConvertedResultExpression(Instruction instruction) {
5252
exists(TranslatedExpr translatedExpr |
5353
translatedExpr = getTranslatedExpr(result) and
54-
instruction = translatedExpr.getResult()
54+
instruction = translatedExpr.getResult() and
55+
// Only associate `instruction` with this expression if the translated
56+
// expression actually produced the instruction; not if it merely
57+
// forwarded the result of another translated expression.
58+
instruction = translatedExpr.getInstruction(_)
5559
)
5660
}
5761

5862
cached
5963
Expr getInstructionUnconvertedResultExpression(Instruction instruction) {
60-
exists(Expr converted, TranslatedExpr translatedExpr |
64+
exists(Expr converted |
6165
result = converted.(Conversion).getExpr+()
6266
or
6367
result = converted
6468
|
6569
not result instanceof Conversion and
66-
translatedExpr = getTranslatedExpr(converted) and
67-
instruction = translatedExpr.getResult()
70+
converted = getInstructionConvertedResultExpression(instruction)
6871
)
6972
}
7073

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ newtype TInstructionTag =
4545
ConditionValueResultLoadTag() or
4646
BoolConversionConstantTag() or
4747
BoolConversionCompareTag() or
48+
ResultCopyTag() or
4849
LoadTag() or // Implicit load due to lvalue-to-rvalue conversion
4950
CatchTag() or
5051
ThrowTag() or

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ private import InstructionTag
99
private import TranslatedCondition
1010
private import TranslatedFunction
1111
private import TranslatedStmt
12+
private import TranslatedExpr
1213
private import IRConstruction
1314
private import semmle.code.cpp.models.interfaces.SideEffect
1415

@@ -235,6 +236,15 @@ newtype TTranslatedElement =
235236
expr.hasLValueToRValueConversion() and
236237
not ignoreLoad(expr)
237238
} or
239+
TTranslatedResultCopy(Expr expr) {
240+
not ignoreExpr(expr) and
241+
exprNeedsCopyIfNotLoaded(expr) and
242+
// Doesn't have a TTranslatedLoad
243+
not (
244+
expr.hasLValueToRValueConversion() and
245+
not ignoreLoad(expr)
246+
)
247+
} or
238248
// An expression most naturally translated as control flow.
239249
TTranslatedNativeCondition(Expr expr) {
240250
not ignoreExpr(expr) and

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll

Lines changed: 117 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,11 @@ abstract class TranslatedExpr extends TranslatedElement {
6262
/**
6363
* Holds if the result of this `TranslatedExpr` is a glvalue.
6464
*/
65-
private predicate isResultGLValue() {
65+
predicate isResultGLValue() {
66+
// This implementation is overridden in `TranslatedCoreExpr` to mark them
67+
// as glvalues if they have loads on them. It's not overridden in
68+
// `TranslatedResultCopy` since result copies never have loads.
6669
expr.isGLValueCategory()
67-
or
68-
// If this TranslatedExpr doesn't produce the result, then it must represent
69-
// a glvalue that is then loaded by a TranslatedLoad.
70-
not producesExprResult()
7170
}
7271

7372
final override Locatable getAST() { result = expr }
@@ -96,14 +95,28 @@ abstract class TranslatedExpr extends TranslatedElement {
9695
abstract class TranslatedCoreExpr extends TranslatedExpr {
9796
final override string toString() { result = expr.toString() }
9897

98+
/**
99+
* Holds if the result of this `TranslatedExpr` is a glvalue.
100+
*/
101+
override predicate isResultGLValue() {
102+
super.isResultGLValue()
103+
or
104+
// If this TranslatedExpr doesn't produce the result, then it must represent
105+
// a glvalue that is then loaded by a TranslatedLoad.
106+
hasLoad()
107+
}
108+
109+
final predicate hasLoad() {
110+
expr.hasLValueToRValueConversion() and
111+
not ignoreLoad(expr)
112+
}
113+
99114
final override predicate producesExprResult() {
100115
// If there's no load, then this is the only TranslatedExpr for this
101116
// expression.
102-
not expr.hasLValueToRValueConversion()
103-
or
104-
// If we're supposed to ignore the load on this expression, then this
105-
// is the only TranslatedExpr.
106-
ignoreLoad(expr)
117+
not hasLoad() and
118+
// If there's a result copy, then this expression's result is the copy.
119+
not exprNeedsCopyIfNotLoaded(expr)
107120
}
108121
}
109122

@@ -288,6 +301,48 @@ class TranslatedLoad extends TranslatedExpr, TTranslatedLoad {
288301
private TranslatedCoreExpr getOperand() { result.getExpr() = expr }
289302
}
290303

304+
/**
305+
* IR translation of an implicit lvalue-to-rvalue conversion on the result of
306+
* an expression.
307+
*/
308+
class TranslatedResultCopy extends TranslatedExpr, TTranslatedResultCopy {
309+
TranslatedResultCopy() { this = TTranslatedResultCopy(expr) }
310+
311+
override string toString() { result = "Result of " + expr.toString() }
312+
313+
override Instruction getFirstInstruction() { result = getOperand().getFirstInstruction() }
314+
315+
override TranslatedElement getChild(int id) { id = 0 and result = getOperand() }
316+
317+
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
318+
tag = ResultCopyTag() and
319+
opcode instanceof Opcode::CopyValue and
320+
resultType = getOperand().getResultType()
321+
}
322+
323+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
324+
tag = ResultCopyTag() and
325+
result = getParent().getChildSuccessor(this) and
326+
kind instanceof GotoEdge
327+
}
328+
329+
override Instruction getChildSuccessor(TranslatedElement child) {
330+
child = getOperand() and result = getInstruction(ResultCopyTag())
331+
}
332+
333+
override Instruction getResult() { result = getInstruction(ResultCopyTag()) }
334+
335+
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
336+
tag = ResultCopyTag() and
337+
operandTag instanceof UnaryOperandTag and
338+
result = getOperand().getResult()
339+
}
340+
341+
final override predicate producesExprResult() { any() }
342+
343+
private TranslatedCoreExpr getOperand() { result.getExpr() = expr }
344+
}
345+
291346
class TranslatedCommaExpr extends TranslatedNonConstantExpr {
292347
override CommaExpr expr;
293348

@@ -2403,6 +2458,58 @@ class TranslatedErrorExpr extends TranslatedSingleInstructionExpr {
24032458
final override Opcode getOpcode() { result instanceof Opcode::Error }
24042459
}
24052460

2461+
/**
2462+
* Holds if the translation of `expr` will not directly generate any
2463+
* `Instruction` for use as result. For such instructions we can synthesize a
2464+
* `CopyValue` instruction to ensure that there is a 1-to-1 mapping between
2465+
* expressions and result-bearing instructions.
2466+
*/
2467+
// This should ideally be a dispatch predicate on TranslatedNonConstantExpr,
2468+
// but it doesn't look monotonic to QL.
2469+
predicate exprNeedsCopyIfNotLoaded(Expr expr) {
2470+
(
2471+
expr instanceof AssignExpr
2472+
or
2473+
expr instanceof AssignOperation and
2474+
not expr.isPRValueCategory() // is C++
2475+
or
2476+
expr instanceof PrefixCrementOperation and
2477+
not expr.isPRValueCategory() // is C++
2478+
or
2479+
expr instanceof PointerDereferenceExpr
2480+
or
2481+
expr instanceof AddressOfExpr
2482+
or
2483+
expr instanceof BuiltInOperationBuiltInAddressOf
2484+
or
2485+
// No case for ParenthesisExpr to avoid getting too many instructions
2486+
expr instanceof ReferenceDereferenceExpr
2487+
or
2488+
expr instanceof ReferenceToExpr
2489+
or
2490+
expr instanceof CommaExpr
2491+
or
2492+
expr instanceof ConditionDeclExpr
2493+
// TODO: simplify TranslatedStmtExpr too
2494+
) and
2495+
not exprImmediatelyDiscarded(expr)
2496+
}
2497+
2498+
/**
2499+
* Holds if `expr` is immediately discarded. Such expressions do not need a
2500+
* `CopyValue` because it's unlikely that anyone is interested in their value.
2501+
*/
2502+
private predicate exprImmediatelyDiscarded(Expr expr) {
2503+
exists(ExprStmt s |
2504+
s = expr.getParent() and
2505+
not exists(StmtExpr se | s = se.getStmt().(Block).getLastStmt())
2506+
)
2507+
or
2508+
exists(CommaExpr c | c.getLeftOperand() = expr)
2509+
or
2510+
exists(ForStmt for | for.getUpdate() = expr)
2511+
}
2512+
24062513
/**
24072514
* The IR translation of an `__assume` expression. We currently translate these as `NoOp`. In the
24082515
* future, we will probably want to do something better. At a minimum, we can model `__assume(0)` as

cpp/ql/test/library-tests/ir/escape/points_to.expected

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1+
| escape.cpp:111:18:111:21 | CopyValue | no_+0:0 | no_+0:0 |
12
| escape.cpp:115:19:115:28 | PointerAdd[4] | no_+0:0 | no_+0:0 |
3+
| escape.cpp:115:20:115:23 | CopyValue | no_+0:0 | no_+0:0 |
24
| escape.cpp:116:19:116:28 | PointerSub[4] | no_+0:0 | no_+0:0 |
5+
| escape.cpp:116:20:116:23 | CopyValue | no_+0:0 | no_+0:0 |
36
| escape.cpp:117:19:117:26 | PointerAdd[4] | no_+0:0 | no_+0:0 |
7+
| escape.cpp:117:23:117:26 | CopyValue | no_+0:0 | no_+0:0 |
8+
| escape.cpp:118:9:118:12 | CopyValue | no_+0:0 | no_+0:0 |
9+
| escape.cpp:120:12:120:15 | CopyValue | no_+0:0 | no_+0:0 |
10+
| escape.cpp:123:14:123:17 | CopyValue | no_+0:0 | no_+0:0 |
11+
| escape.cpp:124:15:124:18 | CopyValue | no_+0:0 | no_+0:0 |
12+
| escape.cpp:127:9:127:12 | CopyValue | no_+0:0 | no_+0:0 |
13+
| escape.cpp:129:12:129:15 | CopyValue | no_+0:0 | no_+0:0 |
414
| escape.cpp:134:5:134:18 | Convert | no_Array+0:0 | no_Array+0:0 |
515
| escape.cpp:134:11:134:18 | Convert | no_Array+0:0 | no_Array+0:0 |
616
| escape.cpp:135:5:135:12 | Convert | no_Array+0:0 | no_Array+0:0 |
@@ -16,9 +26,14 @@
1626
| escape.cpp:140:21:140:32 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 |
1727
| escape.cpp:141:27:141:27 | FieldAddress[x] | no_Point+0:0 | no_Point+0:0 |
1828
| escape.cpp:142:14:142:14 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
29+
| escape.cpp:143:19:143:27 | CopyValue | no_Point+0:0 | no_Point+0:0 |
1930
| escape.cpp:143:31:143:31 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
31+
| escape.cpp:144:6:144:14 | CopyValue | no_Point+0:0 | no_Point+0:0 |
2032
| escape.cpp:144:18:144:18 | FieldAddress[y] | no_Point+4:0 | no_Point+4:0 |
33+
| escape.cpp:145:20:145:30 | CopyValue | no_Point+8:0 | no_Point+8:0 |
2134
| escape.cpp:145:30:145:30 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 |
35+
| escape.cpp:146:5:146:18 | CopyValue | no_Point+8:0 | no_Point+8:0 |
36+
| escape.cpp:146:7:146:17 | CopyValue | no_Point+8:0 | no_Point+8:0 |
2237
| escape.cpp:146:17:146:17 | FieldAddress[z] | no_Point+8:0 | no_Point+8:0 |
2338
| escape.cpp:149:5:149:14 | ConvertToBase[Derived : Intermediate1] | no_Derived+0:0 | no_Derived+0:0 |
2439
| escape.cpp:149:5:149:14 | ConvertToBase[Intermediate1 : Base] | no_Derived+0:0 | no_Derived+0:0 |
@@ -30,18 +45,42 @@
3045
| escape.cpp:151:16:151:17 | FieldAddress[i2] | no_Derived+16:0 | no_Derived+16:0 |
3146
| escape.cpp:152:19:152:28 | ConvertToBase[Derived : Intermediate2] | no_Derived+12:0 | no_Derived+12:0 |
3247
| escape.cpp:152:30:152:31 | FieldAddress[i2] | no_Derived+16:0 | no_Derived+16:0 |
48+
| escape.cpp:155:17:155:30 | CopyValue | no_ssa_addrOf+0:0 | no_ssa_addrOf+0:0 |
3349
| escape.cpp:155:17:155:30 | Store | no_ssa_addrOf+0:0 | no_ssa_addrOf+0:0 |
50+
| escape.cpp:158:17:158:28 | CopyValue | no_ssa_refTo+0:0 | no_ssa_refTo+0:0 |
3451
| escape.cpp:158:17:158:28 | Store | no_ssa_refTo+0:0 | no_ssa_refTo+0:0 |
3552
| escape.cpp:161:19:161:42 | Convert | no_ssa_refToArrayElement+0:0 | no_ssa_refToArrayElement+0:0 |
53+
| escape.cpp:161:19:161:45 | CopyValue | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 |
3654
| escape.cpp:161:19:161:45 | PointerAdd[4] | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 |
3755
| escape.cpp:161:19:161:45 | Store | no_ssa_refToArrayElement+20:0 | no_ssa_refToArrayElement+20:0 |
56+
| escape.cpp:164:24:164:40 | CopyValue | no_ssa_refToArray+0:0 | no_ssa_refToArray+0:0 |
3857
| escape.cpp:164:24:164:40 | Store | no_ssa_refToArray+0:0 | no_ssa_refToArray+0:0 |
58+
| escape.cpp:167:19:167:28 | CopyValue | passByPtr+0:0 | passByPtr+0:0 |
59+
| escape.cpp:170:21:170:29 | CopyValue | passByRef+0:0 | passByRef+0:0 |
60+
| escape.cpp:173:22:173:38 | CopyValue | no_ssa_passByPtr+0:0 | no_ssa_passByPtr+0:0 |
61+
| escape.cpp:176:24:176:39 | CopyValue | no_ssa_passByRef+0:0 | no_ssa_passByRef+0:0 |
62+
| escape.cpp:179:22:179:42 | CopyValue | no_ssa_passByPtr_ret+0:0 | no_ssa_passByPtr_ret+0:0 |
63+
| escape.cpp:182:24:182:43 | CopyValue | no_ssa_passByRef_ret+0:0 | no_ssa_passByRef_ret+0:0 |
64+
| escape.cpp:185:30:185:40 | CopyValue | passByPtr2+0:0 | passByPtr2+0:0 |
65+
| escape.cpp:188:32:188:41 | CopyValue | passByRef2+0:0 | passByRef2+0:0 |
3966
| escape.cpp:191:30:191:42 | Call | none | passByPtr3+0:0 |
67+
| escape.cpp:191:44:191:54 | CopyValue | passByPtr3+0:0 | passByPtr3+0:0 |
4068
| escape.cpp:194:32:194:46 | Call | none | passByRef3+0:0 |
69+
| escape.cpp:194:32:194:59 | CopyValue | none | passByRef3+0:0 |
70+
| escape.cpp:194:48:194:57 | CopyValue | passByRef3+0:0 | passByRef3+0:0 |
71+
| escape.cpp:199:17:199:34 | CopyValue | no_ssa_passByPtr4+0:0 | no_ssa_passByPtr4+0:0 |
72+
| escape.cpp:199:37:199:54 | CopyValue | no_ssa_passByPtr5+0:0 | no_ssa_passByPtr5+0:0 |
4173
| escape.cpp:202:5:202:19 | Call | none | passByRef6+0:0 |
74+
| escape.cpp:202:5:202:32 | CopyValue | none | passByRef6+0:0 |
75+
| escape.cpp:202:21:202:30 | CopyValue | passByRef6+0:0 | passByRef6+0:0 |
4276
| escape.cpp:205:5:205:19 | Call | none | no_ssa_passByRef7+0:0 |
77+
| escape.cpp:205:5:205:39 | CopyValue | none | no_ssa_passByRef7+0:0 |
78+
| escape.cpp:205:21:205:37 | CopyValue | no_ssa_passByRef7+0:0 | no_ssa_passByRef7+0:0 |
4379
| escape.cpp:209:14:209:25 | Call | none | no_ssa_c+0:0 |
80+
| escape.cpp:217:14:217:16 | CopyValue | c2+0:0 | c2+0:0 |
4481
| escape.cpp:221:8:221:19 | Call | none | c3+0:0 |
4582
| escape.cpp:225:17:225:28 | Call | none | c4+0:0 |
4683
| escape.cpp:247:2:247:27 | Store | condEscape1+0:0 | condEscape1+0:0 |
84+
| escape.cpp:247:16:247:27 | CopyValue | condEscape1+0:0 | condEscape1+0:0 |
4785
| escape.cpp:249:9:249:34 | Store | condEscape2+0:0 | condEscape2+0:0 |
86+
| escape.cpp:249:23:249:34 | CopyValue | condEscape2+0:0 | condEscape2+0:0 |

0 commit comments

Comments
 (0)