Skip to content

Commit a9bcc1d

Browse files
authored
Merge pull request #2667 from dbartol/dbartol/NoEscape
C++/C#: Make escape analysis unsound by default
2 parents c7975e8 + 7df3cf4 commit a9bcc1d

File tree

55 files changed

+2531
-181
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2531
-181
lines changed

config/identical-files.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@
8282
"cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll",
8383
"csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll"
8484
],
85+
"IR IRConfiguration": [
86+
"cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll",
87+
"csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll"
88+
],
89+
"IR UseSoundEscapeAnalysis": [
90+
"cpp/ql/src/semmle/code/cpp/ir/implementation/UseSoundEscapeAnalysis.qll",
91+
"csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll"
92+
],
8593
"IR Operand Tag": [
8694
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll",
8795
"csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll"

cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
/**
2+
* Module used to configure the IR generation process.
3+
*/
4+
15
private import internal.IRConfigurationInternal
26

37
private newtype TIRConfiguration = MkIRConfiguration()
@@ -13,3 +17,18 @@ class IRConfiguration extends TIRConfiguration {
1317
*/
1418
predicate shouldCreateIRForFunction(Language::Function func) { any() }
1519
}
20+
21+
private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration()
22+
23+
/**
24+
* The query can extend this class to control what escape analysis is used when generating SSA.
25+
*/
26+
class IREscapeAnalysisConfiguration extends TIREscapeAnalysisConfiguration {
27+
string toString() { result = "IREscapeAnalysisConfiguration" }
28+
29+
/**
30+
* Holds if the escape analysis done by SSA construction should be sound. By default, the SSA is
31+
* built assuming that no variable's address ever escapes.
32+
*/
33+
predicate useSoundEscapeAnalysis() { none() }
34+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import IRConfiguration
2+
3+
/**
4+
* Overrides the default IR configuration to use sound escape analysis, instead of assuming that
5+
* variable addresses never escape.
6+
*/
7+
class SoundEscapeAnalysisConfiguration extends IREscapeAnalysisConfiguration {
8+
override predicate useSoundEscapeAnalysis() { any() }
9+
}

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ private import AliasAnalysisInternal
22
private import cpp
33
private import InputIR
44
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
5+
private import semmle.code.cpp.ir.implementation.IRConfiguration
56
private import semmle.code.cpp.models.interfaces.Alias
67

78
private class IntValue = Ints::IntValue;
@@ -277,9 +278,14 @@ private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
277278
* analysis.
278279
*/
279280
predicate variableAddressEscapes(IRVariable var) {
280-
automaticVariableAddressEscapes(var.(IRAutomaticVariable))
281+
exists(IREscapeAnalysisConfiguration config |
282+
config.useSoundEscapeAnalysis() and
283+
automaticVariableAddressEscapes(var.(IRAutomaticVariable))
284+
)
281285
or
282-
// All variables with static storage duration have their address escape.
286+
// All variables with static storage duration have their address escape, even when escape analysis
287+
// is allowed to be unsound. Otherwise, we won't have a definition for any non-escaped global
288+
// variable. Normally, we rely on `AliasedDefinition` to handle that.
283289
not var instanceof IRAutomaticVariable
284290
}
285291

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class PropertyProvider extends IRPropertyProvider {
107107
exists(
108108
MemoryLocation useLocation, IRBlock predBlock, IRBlock defBlock, int defIndex, Overlap overlap
109109
|
110-
hasPhiOperandDefinition(_, useLocation, block, predBlock, defBlock, defIndex, overlap) and
110+
hasPhiOperandDefinition(_, useLocation, block, predBlock, defBlock, defIndex) and
111111
key = "PhiUse[" + useLocation.toString() + " from " + predBlock.getDisplayIndex().toString() +
112112
"]" and
113113
result = defBlock.getDisplayIndex().toString() + "_" + defIndex + " (" + overlap.toString() +

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

Lines changed: 12 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -43,93 +43,34 @@ abstract class TranslatedDeclarationEntry extends TranslatedElement, TTranslated
4343
* Represents the IR translation of the declaration of a local variable,
4444
* including its initialization, if any.
4545
*/
46-
abstract class TranslatedVariableDeclaration extends TranslatedElement, InitializationContext {
46+
abstract class TranslatedLocalVariableDeclaration extends TranslatedVariableInitialization {
4747
/**
4848
* Gets the local variable being declared.
4949
*/
5050
abstract LocalVariable getVariable();
5151

52-
override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
52+
final override Type getTargetType() { result = getVariableType(getVariable()) }
5353

54-
override Instruction getFirstInstruction() {
55-
result = getInstruction(InitializerVariableAddressTag())
56-
}
57-
58-
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
59-
tag = InitializerVariableAddressTag() and
60-
opcode instanceof Opcode::VariableAddress and
61-
resultType = getTypeForGLValue(getVariableType(getVariable()))
62-
or
63-
hasUninitializedInstruction() and
64-
tag = InitializerStoreTag() and
65-
opcode instanceof Opcode::Uninitialized and
66-
resultType = getTypeForPRValue(getVariableType(getVariable()))
67-
}
68-
69-
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
70-
(
71-
tag = InitializerVariableAddressTag() and
72-
kind instanceof GotoEdge and
73-
if hasUninitializedInstruction()
74-
then result = getInstruction(InitializerStoreTag())
75-
else result = getInitialization().getFirstInstruction()
76-
)
77-
or
78-
hasUninitializedInstruction() and
79-
kind instanceof GotoEdge and
80-
tag = InitializerStoreTag() and
81-
(
82-
result = getInitialization().getFirstInstruction()
83-
or
84-
not exists(getInitialization()) and result = getParent().getChildSuccessor(this)
85-
)
86-
}
87-
88-
override Instruction getChildSuccessor(TranslatedElement child) {
89-
child = getInitialization() and result = getParent().getChildSuccessor(this)
90-
}
91-
92-
override IRVariable getInstructionVariable(InstructionTag tag) {
93-
(
94-
tag = InitializerVariableAddressTag()
95-
or
96-
hasUninitializedInstruction() and tag = InitializerStoreTag()
97-
) and
98-
result = getIRUserVariable(getFunction(), getVariable())
99-
}
100-
101-
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
102-
hasUninitializedInstruction() and
103-
tag = InitializerStoreTag() and
104-
operandTag instanceof AddressOperandTag and
105-
result = getInstruction(InitializerVariableAddressTag())
106-
}
107-
108-
override Instruction getTargetAddress() {
109-
result = getInstruction(InitializerVariableAddressTag())
110-
}
111-
112-
override Type getTargetType() { result = getVariableType(getVariable()) }
113-
114-
private TranslatedInitialization getInitialization() {
54+
final override TranslatedInitialization getInitialization() {
11555
result = getTranslatedInitialization(getVariable()
11656
.getInitializer()
11757
.getExpr()
11858
.getFullyConverted())
11959
}
12060

121-
private predicate hasUninitializedInstruction() {
122-
not exists(getInitialization()) or
123-
getInitialization() instanceof TranslatedListInitialization or
124-
getInitialization() instanceof TranslatedConstructorInitialization or
125-
getInitialization().(TranslatedStringLiteralInitialization).zeroInitRange(_, _)
61+
final override Instruction getInitializationSuccessor() {
62+
result = getParent().getChildSuccessor(this)
63+
}
64+
65+
final override IRVariable getIRVariable() {
66+
result = getIRUserVariable(getFunction(), getVariable())
12667
}
12768
}
12869

12970
/**
13071
* Represents the IR translation of a local variable declaration within a declaration statement.
13172
*/
132-
class TranslatedVariableDeclarationEntry extends TranslatedVariableDeclaration,
73+
class TranslatedVariableDeclarationEntry extends TranslatedLocalVariableDeclaration,
13374
TranslatedDeclarationEntry {
13475
LocalVariable var;
13576

@@ -151,7 +92,7 @@ TranslatedRangeBasedForVariableDeclaration getTranslatedRangeBasedForVariableDec
15192
/**
15293
* Represents the IR translation of a compiler-generated variable in a range-based `for` loop.
15394
*/
154-
class TranslatedRangeBasedForVariableDeclaration extends TranslatedVariableDeclaration,
95+
class TranslatedRangeBasedForVariableDeclaration extends TranslatedLocalVariableDeclaration,
15596
TTranslatedRangeBasedForVariableDeclaration {
15697
RangeBasedForStmt forStmt;
15798
LocalVariable var;
@@ -181,7 +122,7 @@ TranslatedConditionDecl getTranslatedConditionDecl(ConditionDeclExpr expr) {
181122
* }
182123
* ```
183124
*/
184-
class TranslatedConditionDecl extends TranslatedVariableDeclaration, TTranslatedConditionDecl {
125+
class TranslatedConditionDecl extends TranslatedLocalVariableDeclaration, TTranslatedConditionDecl {
185126
ConditionDeclExpr conditionDeclExpr;
186127

187128
TranslatedConditionDecl() { this = TTranslatedConditionDecl(conditionDeclExpr) }

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

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,47 +1932,31 @@ abstract class TranslatedThrowExpr extends TranslatedNonConstantExpr {
19321932
* IR translation of a `throw` expression with an argument
19331933
* (e.g. `throw std::bad_alloc()`).
19341934
*/
1935-
class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContext {
1935+
class TranslatedThrowValueExpr extends TranslatedThrowExpr, TranslatedVariableInitialization {
19361936
TranslatedThrowValueExpr() { not expr instanceof ReThrowExpr }
19371937

1938-
override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
1939-
1940-
override Instruction getFirstInstruction() {
1941-
result = getInstruction(InitializerVariableAddressTag())
1942-
}
1943-
19441938
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
19451939
TranslatedThrowExpr.super.hasInstruction(opcode, tag, resultType)
19461940
or
1947-
tag = InitializerVariableAddressTag() and
1948-
opcode instanceof Opcode::VariableAddress and
1949-
resultType = getTypeForGLValue(getExceptionType())
1941+
TranslatedVariableInitialization.super.hasInstruction(opcode, tag, resultType)
19501942
}
19511943

19521944
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
19531945
result = TranslatedThrowExpr.super.getInstructionSuccessor(tag, kind)
19541946
or
1955-
tag = InitializerVariableAddressTag() and
1956-
result = getInitialization().getFirstInstruction() and
1957-
kind instanceof GotoEdge
1958-
}
1959-
1960-
override Instruction getChildSuccessor(TranslatedElement child) {
1961-
child = getInitialization() and
1962-
result = getInstruction(ThrowTag())
1947+
result = TranslatedVariableInitialization.super.getInstructionSuccessor(tag, kind)
19631948
}
19641949

1965-
override IRVariable getInstructionVariable(InstructionTag tag) {
1966-
tag = InitializerVariableAddressTag() and
1967-
result = getIRTempVariable(expr, ThrowTempVar())
1968-
}
1950+
final override Instruction getInitializationSuccessor() { result = getInstruction(ThrowTag()) }
19691951

19701952
final override predicate hasTempVariable(TempVariableTag tag, CppType type) {
19711953
tag = ThrowTempVar() and
19721954
type = getTypeForPRValue(getExceptionType())
19731955
}
19741956

19751957
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
1958+
result = TranslatedVariableInitialization.super.getInstructionOperand(tag, operandTag)
1959+
or
19761960
tag = ThrowTag() and
19771961
(
19781962
operandTag instanceof AddressOperandTag and
@@ -1989,16 +1973,14 @@ class TranslatedThrowValueExpr extends TranslatedThrowExpr, InitializationContex
19891973
result = getTypeForPRValue(getExceptionType())
19901974
}
19911975

1992-
override Instruction getTargetAddress() {
1993-
result = getInstruction(InitializerVariableAddressTag())
1994-
}
1995-
19961976
override Type getTargetType() { result = getExceptionType() }
19971977

1998-
TranslatedInitialization getInitialization() {
1978+
final override TranslatedInitialization getInitialization() {
19991979
result = getTranslatedInitialization(expr.getExpr().getFullyConverted())
20001980
}
20011981

1982+
final override IRVariable getIRVariable() { result = getIRTempVariable(expr, ThrowTempVar()) }
1983+
20021984
final override Opcode getThrowOpcode() { result instanceof Opcode::ThrowValue }
20031985

20041986
private Type getExceptionType() { result = expr.getType() }

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

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,98 @@ abstract class InitializationContext extends TranslatedElement {
3030
abstract Type getTargetType();
3131
}
3232

33+
/**
34+
* Base class for any element that initializes a stack variable. Examples include local variable
35+
* declarations, `return` statements, and `throw` expressions.
36+
*/
37+
abstract class TranslatedVariableInitialization extends TranslatedElement, InitializationContext {
38+
final override TranslatedElement getChild(int id) { id = 0 and result = getInitialization() }
39+
40+
final override Instruction getFirstInstruction() {
41+
result = getInstruction(InitializerVariableAddressTag())
42+
}
43+
44+
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
45+
tag = InitializerVariableAddressTag() and
46+
opcode instanceof Opcode::VariableAddress and
47+
resultType = getTypeForGLValue(getTargetType())
48+
or
49+
hasUninitializedInstruction() and
50+
tag = InitializerStoreTag() and
51+
opcode instanceof Opcode::Uninitialized and
52+
resultType = getTypeForPRValue(getTargetType())
53+
}
54+
55+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
56+
(
57+
tag = InitializerVariableAddressTag() and
58+
kind instanceof GotoEdge and
59+
if hasUninitializedInstruction()
60+
then result = getInstruction(InitializerStoreTag())
61+
else result = getInitialization().getFirstInstruction()
62+
)
63+
or
64+
hasUninitializedInstruction() and
65+
kind instanceof GotoEdge and
66+
tag = InitializerStoreTag() and
67+
(
68+
result = getInitialization().getFirstInstruction()
69+
or
70+
not exists(getInitialization()) and result = getInitializationSuccessor()
71+
)
72+
}
73+
74+
final override Instruction getChildSuccessor(TranslatedElement child) {
75+
child = getInitialization() and result = getInitializationSuccessor()
76+
}
77+
78+
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
79+
hasUninitializedInstruction() and
80+
tag = InitializerStoreTag() and
81+
operandTag instanceof AddressOperandTag and
82+
result = getInstruction(InitializerVariableAddressTag())
83+
}
84+
85+
final override IRVariable getInstructionVariable(InstructionTag tag) {
86+
(
87+
tag = InitializerVariableAddressTag()
88+
or
89+
hasUninitializedInstruction() and tag = InitializerStoreTag()
90+
) and
91+
result = getIRVariable()
92+
}
93+
94+
final override Instruction getTargetAddress() {
95+
result = getInstruction(InitializerVariableAddressTag())
96+
}
97+
98+
/**
99+
* Get the initialization for the variable.
100+
*/
101+
abstract TranslatedInitialization getInitialization();
102+
103+
/**
104+
* Get the `IRVariable` to be initialized. This may be an `IRTempVariable`.
105+
*/
106+
abstract IRVariable getIRVariable();
107+
108+
/**
109+
* Gets the `Instruction` to be executed immediately after the initialization.
110+
*/
111+
abstract Instruction getInitializationSuccessor();
112+
113+
/**
114+
* Holds if this initialization requires an `Uninitialized` instruction to be emitted before
115+
* evaluating the initializer.
116+
*/
117+
final predicate hasUninitializedInstruction() {
118+
not exists(getInitialization()) or
119+
getInitialization() instanceof TranslatedListInitialization or
120+
getInitialization() instanceof TranslatedConstructorInitialization or
121+
getInitialization().(TranslatedStringLiteralInitialization).zeroInitRange(_, _)
122+
}
123+
}
124+
33125
/**
34126
* Represents the IR translation of any initialization, whether from an
35127
* initializer list or from a direct initializer.

0 commit comments

Comments
 (0)