Skip to content

Commit 396a72d

Browse files
authored
Merge pull request #1898 from AndreiDiaconu1/ircsharp-collections
C# IR: Object creation refactor and collection initializers
2 parents 1f92751 + 43accd3 commit 396a72d

File tree

7 files changed

+317
-231
lines changed

7 files changed

+317
-231
lines changed

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ private import semmle.code.csharp.ir.implementation.internal.OperandTag
44
private import InstructionTag
55
private import TranslatedElement
66
private import TranslatedExpr
7+
private import TranslatedInitialization
78
private import semmle.code.csharp.ir.Util
89
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBase
910
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
@@ -50,7 +51,13 @@ class TranslatedFunctionCall extends TranslatedNonConstantExpr, TranslatedCall {
5051
result = getTranslatedExpr(expr.(QualifiableExpr).getQualifier())
5152
}
5253

53-
override Instruction getQualifierResult() { result = this.getQualifier().getResult() }
54+
override Instruction getQualifierResult() {
55+
// since `ElementInitializer`s do not have a qualifier, the qualifier's result is retrieved
56+
// from the enclosing initialization context
57+
if expr.getParent() instanceof CollectionInitializer
58+
then result = getTranslatedExpr(expr.getParent()).(InitializationContext).getTargetAddress()
59+
else result = this.getQualifier().getResult()
60+
}
5461

5562
override Type getCallResultType() { result = expr.getTarget().getReturnType() }
5663

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

+7-13
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ 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) and
175+
(expr instanceof ObjectCreation or expr instanceof DelegateCreation)
176+
} or
172177
// A separate element to handle the lvalue-to-rvalue conversion step of an
173178
// expression.
174179
TTranslatedLoad(Expr expr) {
@@ -219,32 +224,21 @@ newtype TTranslatedElement =
219224
// we deal with all the types of initialization separately.
220225
// First only simple local variable initialization (ie. `int x = 0`)
221226
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
227+
lvInit.getInitializer() = expr
226228
)
227229
or
228230
// Then treat more complex ones
229-
expr instanceof ObjectCreation
230-
or
231-
expr instanceof DelegateCreation
232-
or
233231
expr instanceof ArrayInitializer
234232
or
235233
expr instanceof ObjectInitializer
236234
or
237-
expr = any(ThrowExpr throw).getExpr()
235+
expr = any(ThrowElement throwElement).getExpr()
238236
or
239237
expr = any(CollectionInitializer colInit).getAnElementInitializer()
240238
or
241239
expr = any(ReturnStmt returnStmt).getExpr()
242240
or
243241
expr = any(ArrayInitializer arrInit).getAnElement()
244-
or
245-
expr = any(LambdaExpr lambda).getSourceDeclaration()
246-
or
247-
expr = any(AnonymousMethodExpr anonMethExpr).getSourceDeclaration()
248242
)
249243
} or
250244
// 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

+141-8
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
/**
@@ -481,11 +485,7 @@ class TranslatedObjectInitializerExpr extends TranslatedNonConstantExpr, Initial
481485
}
482486

483487
override TranslatedElement getChild(int id) {
484-
exists(AssignExpr assign |
485-
result = getTranslatedExpr(expr.getChild(id)) and
486-
expr.getAChild() = assign and
487-
assign.getIndex() = id
488-
)
488+
result = getTranslatedExpr(expr.getMemberInitializer(id))
489489
}
490490

491491
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
@@ -499,9 +499,57 @@ class TranslatedObjectInitializerExpr extends TranslatedNonConstantExpr, Initial
499499
)
500500
}
501501

502-
override Instruction getTargetAddress() { result = this.getParent().getInstruction(NewObjTag()) }
502+
override Instruction getTargetAddress() {
503+
// The target address is the address of the newly allocated object,
504+
// which can be retrieved from the parent `TranslatedObjectCreation`.
505+
result = this.getParent().getInstruction(NewObjTag())
506+
}
507+
508+
override Type getTargetType() {
509+
result = this.getParent().getInstruction(NewObjTag()).getResultType()
510+
}
511+
}
512+
513+
class TranslatedCollectionInitializer extends TranslatedNonConstantExpr, InitializationContext {
514+
override CollectionInitializer expr;
515+
516+
override Instruction getResult() { none() }
517+
518+
override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() }
519+
520+
override predicate hasInstruction(
521+
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
522+
) {
523+
none()
524+
}
525+
526+
override TranslatedElement getChild(int id) {
527+
result = getTranslatedExpr(expr.getElementInitializer(id))
528+
}
529+
530+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
531+
532+
override Instruction getChildSuccessor(TranslatedElement child) {
533+
exists(int index |
534+
child = this.getChild(index) and
535+
(
536+
result = this.getChild(index + 1).getFirstInstruction()
537+
or
538+
not exists(this.getChild(index + 1)) and
539+
result = this.getParent().getChildSuccessor(this)
540+
)
541+
)
542+
}
543+
544+
override Instruction getTargetAddress() {
545+
// The target address is the address of the newly allocated object,
546+
// which can be retrieved from the parent `TranslatedObjectCreation`.
547+
result = this.getParent().getInstruction(NewObjTag())
548+
}
503549

504-
override Type getTargetType() { none() }
550+
override Type getTargetType() {
551+
result = this.getParent().getInstruction(NewObjTag()).getResultType()
552+
}
505553
}
506554

507555
/**
@@ -1918,3 +1966,88 @@ class TranslatedDelegateCall extends TranslatedNonConstantExpr {
19181966
result = DelegateElements::getInvoke(expr)
19191967
}
19201968
}
1969+
1970+
/**
1971+
* Represents the IR translation of creation expression. Can be the translation of an
1972+
* `ObjectCreation` or a `DelegateCreation`.
1973+
* The `NewObj` instruction denotes the fact that during initialization a new
1974+
* object is allocated, which is then initialized by the constructor.
1975+
*/
1976+
abstract class TranslatedCreation extends TranslatedCoreExpr, TTranslatedCreationExpr,
1977+
ConstructorCallContext {
1978+
TranslatedCreation() { this = TTranslatedCreationExpr(expr) }
1979+
1980+
override TranslatedElement getChild(int id) {
1981+
id = 0 and result = this.getConstructorCall()
1982+
or
1983+
id = 1 and result = this.getInitializerExpr()
1984+
}
1985+
1986+
override predicate hasInstruction(
1987+
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
1988+
) {
1989+
// Instruction that allocated space for a new object,
1990+
// and returns its address
1991+
tag = NewObjTag() and
1992+
opcode instanceof Opcode::NewObj and
1993+
resultType = expr.getType() and
1994+
isLValue = false
1995+
}
1996+
1997+
final override Instruction getFirstInstruction() { result = this.getInstruction(NewObjTag()) }
1998+
1999+
override Instruction getResult() { result = getInstruction(NewObjTag()) }
2000+
2001+
override Instruction getReceiver() { result = getInstruction(NewObjTag()) }
2002+
2003+
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
2004+
kind instanceof GotoEdge and
2005+
tag = NewObjTag() and
2006+
result = this.getConstructorCall().getFirstInstruction()
2007+
}
2008+
2009+
override Instruction getChildSuccessor(TranslatedElement child) {
2010+
(
2011+
child = this.getConstructorCall() and
2012+
if exists(this.getInitializerExpr())
2013+
then result = this.getInitializerExpr().getFirstInstruction()
2014+
else result = this.getParent().getChildSuccessor(this)
2015+
)
2016+
or
2017+
child = this.getInitializerExpr() and
2018+
result = this.getParent().getChildSuccessor(this)
2019+
}
2020+
2021+
abstract TranslatedElement getConstructorCall();
2022+
2023+
abstract TranslatedExpr getInitializerExpr();
2024+
}
2025+
2026+
/**
2027+
* Represents the IR translation of an `ObjectCreation`.
2028+
*/
2029+
class TranslatedObjectCreation extends TranslatedCreation {
2030+
override ObjectCreation expr;
2031+
2032+
override TranslatedExpr getInitializerExpr() { result = getTranslatedExpr(expr.getInitializer()) }
2033+
2034+
override TranslatedConstructorCall getConstructorCall() {
2035+
// Since calls are also expressions, we can't
2036+
// use the predicate getTranslatedExpr (since that would
2037+
// also return `this`).
2038+
result.getAST() = this.getAST()
2039+
}
2040+
}
2041+
2042+
/**
2043+
* Represents the IR translation of a `DelegateCreation`.
2044+
*/
2045+
class TranslatedDelegateCreation extends TranslatedCreation {
2046+
override DelegateCreation expr;
2047+
2048+
override TranslatedExpr getInitializerExpr() { none() }
2049+
2050+
override TranslatedElement getConstructorCall() {
2051+
result = DelegateElements::getConstructor(expr)
2052+
}
2053+
}

0 commit comments

Comments
 (0)