Skip to content

Commit 0528d8e

Browse files
author
AndreiDiaconu1
committed
C# IR: Object creation refactoring
The way object creation was translated has been changed: now creations are treated as expressions. The main motivation for this was the inability to have creation expressions as arguments to function calls (a test case has been added to showcase this). All code that dealt with creation expressions has been moved from `TranslatedInitialization.qll` to `TranslatedExpr.qll`. Some light refactoring has also been done, mainly removing code that was useless after the changes mentioned above.
1 parent ad4715f commit 0528d8e

File tree

5 files changed

+197
-223
lines changed

5 files changed

+197
-223
lines changed

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

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ newtype TTranslatedElement =
169169
not isNativeCondition(expr) and
170170
not isFlexibleCondition(expr)
171171
} or
172+
// A creation expression
173+
TTranslatedCreationExpr(Expr expr) {
174+
not ignoreExpr(expr)
175+
} or
172176
// A separate element to handle the lvalue-to-rvalue conversion step of an
173177
// expression.
174178
TTranslatedLoad(Expr expr) {
@@ -219,32 +223,21 @@ newtype TTranslatedElement =
219223
// we deal with all the types of initialization separately.
220224
// First only simple local variable initialization (ie. `int x = 0`)
221225
exists(LocalVariableDeclAndInitExpr lvInit |
222-
lvInit.getInitializer() = expr and
223-
not expr instanceof ArrayCreation and
224-
not expr instanceof ObjectCreation and
225-
not expr instanceof DelegateCreation
226+
lvInit.getInitializer() = expr
226227
)
227228
or
228229
// Then treat more complex ones
229-
expr instanceof ObjectCreation
230-
or
231-
expr instanceof DelegateCreation
232-
or
233230
expr instanceof ArrayInitializer
234231
or
235232
expr instanceof ObjectInitializer
236233
or
237-
expr = any(ThrowExpr throw).getExpr()
234+
expr = any(ThrowStmt throwStmt).getExpr()
238235
or
239236
expr = any(CollectionInitializer colInit).getAnElementInitializer()
240237
or
241238
expr = any(ReturnStmt returnStmt).getExpr()
242239
or
243240
expr = any(ArrayInitializer arrInit).getAnElement()
244-
or
245-
expr = any(LambdaExpr lambda).getSourceDeclaration()
246-
or
247-
expr = any(AnonymousMethodExpr anonMethExpr).getSourceDeclaration()
248241
)
249242
} or
250243
// The initialization of an array element via a member of an initializer list.

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

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
2424
*/
2525
TranslatedExpr getTranslatedExpr(Expr expr) {
2626
result.getExpr() = expr and
27-
result.producesExprResult()
27+
result.producesExprResult() and
28+
// When a constructor call is needed, we fetch it manually.
29+
// This is because of how we translate object creations: the translated expression
30+
// and the translated constructor call are attached to the same element.
31+
(expr instanceof ObjectCreation implies not result instanceof TranslatedConstructorCall)
2832
}
2933

3034
/**
@@ -1918,3 +1922,91 @@ class TranslatedDelegateCall extends TranslatedNonConstantExpr {
19181922
result = DelegateElements::getInvoke(expr)
19191923
}
19201924
}
1925+
1926+
/**
1927+
* Represents the IR translation of creation expression. Can be the translation of an
1928+
* `ObjectCreation` or a `DelegateCreation`.
1929+
* The `NewObj` instruction denotes the fact that during initialization a new
1930+
* object is allocated, which is then initialized by the constructor.
1931+
*/
1932+
abstract class TranslatedCreation extends TranslatedCoreExpr, TTranslatedCreationExpr,
1933+
ConstructorCallContext {
1934+
TranslatedCreation() { this = TTranslatedCreationExpr(expr) }
1935+
1936+
override TranslatedElement getChild(int id) {
1937+
id = 0 and result = this.getConstructorCall()
1938+
or
1939+
id = 1 and result = this.getInitializerExpr()
1940+
}
1941+
1942+
override predicate hasInstruction(
1943+
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
1944+
) {
1945+
// Instruction that allocated space for a new object,
1946+
// and returns its address
1947+
tag = NewObjTag() and
1948+
opcode instanceof Opcode::NewObj and
1949+
resultType = expr.getType() and
1950+
isLValue = false
1951+
}
1952+
1953+
final override Instruction getFirstInstruction() { result = this.getInstruction(NewObjTag()) }
1954+
1955+
override Instruction getResult() { result = getInstruction(NewObjTag()) }
1956+
1957+
override Instruction getReceiver() { result = getInstruction(NewObjTag()) }
1958+
1959+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
1960+
kind instanceof GotoEdge and
1961+
tag = NewObjTag() and
1962+
result = this.getConstructorCall().getFirstInstruction()
1963+
}
1964+
1965+
override Instruction getChildSuccessor(TranslatedElement child) {
1966+
(
1967+
child = this.getConstructorCall() and
1968+
if exists(this.getInitializerExpr())
1969+
then result = this.getInitializerExpr().getFirstInstruction()
1970+
else result = this.getParent().getChildSuccessor(this)
1971+
)
1972+
or
1973+
child = this.getInitializerExpr() and
1974+
result = this.getParent().getChildSuccessor(this)
1975+
}
1976+
1977+
abstract TranslatedElement getConstructorCall();
1978+
1979+
abstract TranslatedExpr getInitializerExpr();
1980+
}
1981+
1982+
/**
1983+
* Represents the IR translation of an `ObjectCreation`.
1984+
*/
1985+
class TranslatedObjectCreation extends TranslatedCreation {
1986+
override ObjectCreation expr;
1987+
1988+
override TranslatedExpr getInitializerExpr() { result = getTranslatedExpr(expr.getInitializer()) }
1989+
1990+
override TranslatedExpr getConstructorCall() {
1991+
// Since calls are also expressions, we can't
1992+
// use the predicate getTranslatedExpr (since that would
1993+
// also return `this`).
1994+
exists(TranslatedConstructorCall cc |
1995+
cc.getAST() = this.getAST() and
1996+
result = cc
1997+
)
1998+
}
1999+
}
2000+
2001+
/**
2002+
* Represents the IR translation of a `DelegateCreation`.
2003+
*/
2004+
class TranslatedDelegateCreation extends TranslatedCreation {
2005+
override DelegateCreation expr;
2006+
2007+
override TranslatedExpr getInitializerExpr() { none() }
2008+
2009+
override TranslatedElement getConstructorCall() {
2010+
result = DelegateElements::getConstructor(expr)
2011+
}
2012+
}

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

Lines changed: 23 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,9 @@ class TranslatedArrayListInitialization extends TranslatedListInitialization {
123123
*/
124124
class TranslatedDirectInitialization extends TranslatedInitialization {
125125
TranslatedDirectInitialization() {
126-
// TODO: Make sure this is complete and correct
127126
not expr instanceof ArrayInitializer and
128127
not expr instanceof ObjectInitializer and
129-
not expr instanceof DelegateCreation and
130-
not expr instanceof CollectionInitializer and
131-
not expr instanceof ObjectCreation and
132-
not expr instanceof StringLiteral
128+
not expr instanceof CollectionInitializer
133129
}
134130

135131
override TranslatedElement getChild(int id) { id = 0 and result = this.getInitializer() }
@@ -145,64 +141,6 @@ class TranslatedDirectInitialization extends TranslatedInitialization {
145141
opcode instanceof Opcode::Store and
146142
resultType = this.getContext().getTargetType() and
147143
isLValue = false
148-
}
149-
150-
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
151-
tag = InitializerStoreTag() and
152-
result = this.getParent().getChildSuccessor(this) and
153-
kind instanceof GotoEdge
154-
}
155-
156-
override Instruction getChildSuccessor(TranslatedElement child) {
157-
child = this.getInitializer() and result = this.getInstruction(InitializerStoreTag())
158-
}
159-
160-
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
161-
tag = InitializerStoreTag() and
162-
(
163-
operandTag instanceof AddressOperandTag and
164-
result = this.getContext().getTargetAddress()
165-
or
166-
operandTag instanceof StoreValueOperandTag and
167-
result = this.getInitializer().getResult()
168-
)
169-
}
170-
171-
TranslatedExpr getInitializer() { result = getTranslatedExpr(expr) }
172-
}
173-
174-
/**
175-
* Represents the IR translation of an initialization from a constructor.
176-
* The `NewObj` instruction denotes the fact that during initialization a new
177-
* object of type `expr.getType()` is allocated, which is then initialized by the
178-
* constructor.
179-
*/
180-
class TranslatedObjectInitialization extends TranslatedInitialization, ConstructorCallContext {
181-
override ObjectCreation expr;
182-
183-
override TranslatedElement getChild(int id) {
184-
id = 0 and result = this.getConstructorCall()
185-
or
186-
id = 1 and result = this.getInitializerExpr()
187-
}
188-
189-
override predicate hasInstruction(
190-
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
191-
) {
192-
// Instruction that allocated space for a new object,
193-
// and returns its address
194-
tag = NewObjTag() and
195-
opcode instanceof Opcode::NewObj and
196-
resultType = expr.getType() and
197-
isLValue = false
198-
or
199-
// Store op used to assign the variable that
200-
// is initialized the address of the newly allocated
201-
// object
202-
tag = InitializerStoreTag() and
203-
opcode instanceof Opcode::Store and
204-
resultType = expr.getType() and
205-
isLValue = false
206144
or
207145
needsConversion() and
208146
tag = AssignmentConvertRightTag() and
@@ -214,39 +152,22 @@ class TranslatedObjectInitialization extends TranslatedInitialization, Construct
214152
isLValue = false
215153
}
216154

217-
final override Instruction getFirstInstruction() { result = this.getInstruction(NewObjTag()) }
218-
219155
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
220-
kind instanceof GotoEdge and
221-
(
222-
tag = NewObjTag() and
223-
result = this.getConstructorCall().getFirstInstruction()
224-
or
225-
tag = InitializerStoreTag() and
226-
result = this.getParent().getChildSuccessor(this)
227-
or
228-
tag = AssignmentConvertRightTag() and
229-
result = this.getInstruction(InitializerStoreTag())
230-
)
156+
tag = InitializerStoreTag() and
157+
result = this.getParent().getChildSuccessor(this) and
158+
kind instanceof GotoEdge
159+
or
160+
needsConversion() and
161+
tag = AssignmentConvertRightTag() and
162+
result = getInstruction(InitializerStoreTag()) and
163+
kind instanceof GotoEdge
231164
}
232165

233166
override Instruction getChildSuccessor(TranslatedElement child) {
234-
(
235-
child = this.getConstructorCall() and
236-
if exists(this.getInitializerExpr())
237-
then result = this.getInitializerExpr().getFirstInstruction()
238-
else
239-
if this.needsConversion()
240-
then result = this.getInstruction(AssignmentConvertRightTag())
241-
else result = this.getInstruction(InitializerStoreTag())
242-
)
243-
or
244-
(
245-
child = this.getInitializerExpr() and
246-
if this.needsConversion()
247-
then result = this.getInstruction(AssignmentConvertRightTag())
248-
else result = this.getInstruction(InitializerStoreTag())
249-
)
167+
child = this.getInitializer() and
168+
if this.needsConversion()
169+
then result = this.getInstruction(AssignmentConvertRightTag())
170+
else result = this.getInstruction(InitializerStoreTag())
250171
}
251172

252173
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -256,33 +177,28 @@ class TranslatedObjectInitialization extends TranslatedInitialization, Construct
256177
result = this.getParent().(InitializationContext).getTargetAddress()
257178
or
258179
(
180+
operandTag instanceof AddressOperandTag and
181+
result = this.getContext().getTargetAddress()
182+
or
259183
operandTag instanceof StoreValueOperandTag and
260-
if needsConversion()
261-
then result = this.getInstruction(AssignmentConvertRightTag())
262-
else result = this.getInstruction(NewObjTag())
184+
result = this.getInitializer().getResult()
263185
)
264186
)
265187
or
266188
tag = AssignmentConvertRightTag() and
267189
operandTag instanceof UnaryOperandTag and
190+
result = this.getInitializer().getResult()
191+
or
192+
tag = AssignmentConvertRightTag() and
193+
operandTag instanceof UnaryOperandTag and
268194
result = this.getInstruction(NewObjTag())
269195
}
270196

271-
private TranslatedExpr getConstructorCall() { result = getTranslatedExpr(expr) }
272-
273-
private TranslatedExpr getInitializerExpr() { result = getTranslatedExpr(expr.getInitializer()) }
274-
275-
override Instruction getReceiver() {
276-
// The newly allocated object will be the target of the constructor call
277-
result = this.getInstruction(NewObjTag())
278-
}
197+
TranslatedExpr getInitializer() { result = getTranslatedExpr(expr) }
279198

280199
private predicate needsConversion() { expr.getType() != this.getContext().getTargetType() }
281200
}
282201

283-
//private string getZeroValue(Type type) {
284-
// if type instanceof FloatingPointType then result = "0.0" else result = "0"
285-
//}
286202
/**
287203
* Represents the IR translation of the initialization of an array element from
288204
* an element of an initializer list.
@@ -424,7 +340,7 @@ class TranslatedConstructorInitializer extends TranslatedConstructorCallFromCons
424340
TTranslatedConstructorInitializer {
425341
TranslatedConstructorInitializer() { this = TTranslatedConstructorInitializer(call) }
426342

427-
override string toString() { result = "constuructor init: " + call.toString() }
343+
override string toString() { result = "constructor init: " + call.toString() }
428344

429345
override Instruction getFirstInstruction() {
430346
if needsConversion()
@@ -472,58 +388,3 @@ class TranslatedConstructorInitializer extends TranslatedConstructorCallFromCons
472388
derivedClass = this.getFunction().getDeclaringType()
473389
}
474390
}
475-
476-
/**
477-
* Represents the IR translation of a delegate creation.
478-
*/
479-
class TranslatedDelegateCreation extends TranslatedInitialization, ConstructorCallContext {
480-
override DelegateCreation expr;
481-
482-
override TranslatedElement getChild(int id) { id = 0 and result = getConstructorCall() }
483-
484-
override predicate hasInstruction(
485-
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
486-
) {
487-
tag = NewObjTag() and
488-
opcode instanceof Opcode::NewObj and
489-
resultType = expr.getType() and
490-
isLValue = false
491-
or
492-
tag = InitializerStoreTag() and
493-
opcode instanceof Opcode::Store and
494-
resultType = expr.getType() and
495-
isLValue = false
496-
}
497-
498-
final override Instruction getFirstInstruction() { result = getInstruction(NewObjTag()) }
499-
500-
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
501-
tag = NewObjTag() and
502-
result = getConstructorCall().getFirstInstruction() and
503-
kind instanceof GotoEdge
504-
or
505-
tag = InitializerStoreTag() and
506-
result = getParent().getChildSuccessor(this) and
507-
kind instanceof GotoEdge
508-
}
509-
510-
override Instruction getChildSuccessor(TranslatedElement child) {
511-
child = getConstructorCall() and
512-
result = getInstruction(InitializerStoreTag())
513-
}
514-
515-
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
516-
tag = InitializerStoreTag() and
517-
(
518-
operandTag instanceof AddressOperandTag and
519-
result = getParent().(InitializationContext).getTargetAddress()
520-
or
521-
operandTag instanceof StoreValueOperandTag and
522-
result = getInstruction(NewObjTag())
523-
)
524-
}
525-
526-
private TranslatedElement getConstructorCall() { result = DelegateElements::getConstructor(expr) }
527-
528-
override Instruction getReceiver() { result = getInstruction(NewObjTag()) }
529-
}

0 commit comments

Comments
 (0)